堆排序(基本思想以及算法实现)

1、引言

简单选择排序算法是通过比较,确定最终的位置。假设未排序的元素个数为N,则遍历一趟,需要比较N-1次,再遍历下一趟时,需比较N-2次。但是,第二次的比较是完全独立的,没有利用第一次比较的信息,因为第一次比较时也没有把比较信息保留下来。那么能否找到一种方法,可以将本趟比较信息记录下来,以供下一次求最值时使用,从而达到减少比较次数的目的呢?

下面介绍的堆排序就是一种利用堆的性质来进行的选择排序。堆排序正是利用一位数组可表示完全二叉树,从而借助完全二叉树的性质来保存比较信息。

这里我们只介绍大顶堆,大顶堆满足以下基本性质:Key[i]>=Key[2i+1]&&key>=key[2i+2],根据大顶堆的性质易知堆顶的关键字肯定是所有关键字中最大的。

2、堆排序的基本思想(大顶堆)

1) 先将初始排列关键字序列(R1,R2…,Rn-1,Rn)构成大顶堆,此堆为初始的无序区.(这里是从最后一个非叶结点向前进行赛选)

2)将堆顶元素R1与最后一个元素Rn交换,此时得到新的无序区(R1,R2…,Rn-1)和新的有序区(Rn),并且Rn大于无序区所有数,此后还有n-1个数;

3)由于交换后新的堆顶R1可能违反堆的性质,因此需要对当前无序区(R1,R2…,Rn-1)调整为新堆(将堆顶元素向下调整使其保持大顶堆的性质,输出堆顶元素),此后还剩余n-2个数;

4)重读以上算法,直到堆中仅剩一个元素为止.

3、基本算法如下:

void heapAjust(int arr[], int s, int len)  
{  
    int temp = arr[s];  //暂存最大结点
    int i;  
    for (i = 2 * s; i <= len; i *= 2)  //从s的左孩子结点开始比较
    {  
        if ((i < len) && (arr[i] < arr[i+1]))  
           i++;  
        if(arr[i] <= temp)  
           break;  
        arr[s] = arr[i];  //将a[i]调整到双亲结点上
        s = i;  //修改s的值,以便继续向下赛选
    }  
    arr[s] = temp;   
}  
//堆排序  
void heapSort(int arr[],int len)  
{  
    int i;  
    for (i = len / 2; i > 0; i--)  
        heapAjust(arr,i,len);    //建堆,从最后一个非叶结点反复调整的过程
    for (i = len; i > 1; i--)  
    {  
        swap(arr[1],arr[i]);     
        heapAjust(arr,1,i - 1);  //每次循环之后所需处理的元素个数减1
    }  
}   

4、堆排序小结

堆排序的最坏时间复杂度为O(N*logN),其平均性能较接近于最坏性能。由于初始建堆所需比较的次数较多,所以堆排序不适合记录数较少的文件,其空间复杂度是O(1),它是一种不稳定的排序算法.

    原文作者:排序算法
    原文地址: https://blog.csdn.net/qiyingrunhua/article/details/13614421
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞