排序算法 -- 堆排序

来源:互联网 发布:淘宝客服上哪儿应聘 编辑:程序博客网 时间:2024/06/03 15:57

一.  堆排序

       1.  堆:类似于完全二叉树,有a1,a2,a3, ...  an,个元素,且第 2*i+1 和 2*i+2 位置的关键字都小于或大于第 i 位置的关键字。

       2.  大根堆与小根堆

            大根堆:堆中的所有元素都满足第 2*i+1 和 2*i+2 位置的关键字都小于第 i 位置的关键字。

            小根堆:堆中的所有元素都满足第 2*i+1 和 2*i+2 位置的关键字都大于第 i 位置的关键字。

       3.  堆排序:利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

二.  原理

       1.  用大根堆排序的基本思想

               ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
               ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
               ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
               ……
               直到无序区只有一个元素为止。
        2.  例如:对数据进行排列如下图:

三.  代码实现 -- 大根堆排序

#includeusing namespace std;//一次堆调整 -- 大根堆static heap(int* arr, int start, int end){    int parent = start;    int tmp = arr[i];    for(int i=parent*2+1; i<=end; i=i*2+1)    {        if(i+1 <= end && arr[i] < arr[i+1])        {            i++;        }        if(tmp < arr[i])        {            arr[parent] = arr[i];            parent = i;        }        else        {            break;        }    }    arr[parent] = tmp;}//堆排序 -- 大根堆void heapSort(int* arr, int len){    if(arr == NULL || len <= 0)    {        return;    }    //建立大根堆    for(int i=(len-1-1)/2; i>=0; i--)    {        heap(arr,i,len-1);    }    //一次堆调整    for(int i=0; i

四.  时间复杂度和空间复杂度及稳定性

       1.  时间复杂度

            首先建立大根堆时,需要从(len-1-1)/2处不断调整,整个是线性的过程时间复杂度为O(n),然后对len-1个数据进行一次堆调整,直至无序区只剩下一个数据,这个过程的时间复杂度为O((n-1)*lgn),所以整个排序过程总的算下来为O(n*lgn)。

       2.  空间复杂度

            纵观整个排序过程除了局部临时变量外,未借用其它额外的空间,所以空间复杂度为O(1)。

       3.  稳定性

            无论是代码还是例图我们都可以看出,堆排序过程中是2*i+1 或 2*i+2 位置的关键字与 i 处的进行交换,这种跳跃式的数据交换使得此排序不稳定。