堆排序

来源:互联网 发布:php数组按id排序 编辑:程序博客网 时间:2024/06/06 07:52

堆排序


参考资料

算法导论

2 数据结构(C语言版)


堆的概述

二叉 堆数据结构是一种数组对象,它可以被视为一颗完全二叉树。树中每个节点与数组中存放该节点值的那个元素对应。数的每一层都是填满的,最后一层可能除外。表示堆的数组A是一个具有两个属性的对象:length [ A ] 是数组中的元素个数,heap-size [A] 是存放在中的堆的元素个数。

根据完全二叉树的性质,我们可以总结出如下性质:数的根为A [ 1 ] ,对于某个结点的下标 ,其父节点为 Parent[i] = i/2 ,左孩子 Left[ i ] = 2*i ,右孩子 Right[ i ] = 2*i + 1,该部分的结论是显而易见的。可参考二叉树章节)

在具体的代码实现中,左孩子2*i 可通过左移1位来实现,即i << 1;同理,右孩子为左移1位加1或者与1作或运算,即 i << 1 + 1 或 i << 1|1 ;父节点为 i >> 1 。算法导论中建议将这些计算过程通过“宏”或“内联函数”实现。

二叉堆有两种:大堆 大根堆 和小堆 小根堆 )。大堆与小堆内部的节点需要满足堆的特点。对于大堆来说,节点i (非根节点的值 <= i 的父节点的值,根节点是最大的值。

对于小堆来说,节点i ( 非根节点的值 <= i 的左右孩子节点的值,根节点的值时最小的。

堆可以被看成是一棵树,而且是一颗完全二叉树,假设该堆有 个节点,那么该堆的高度为 lg n 

 

建小堆过程

现有8个元素的无序序列A = { 49,38,65,97,76,13,27,49 },将该序列建立为一个完全二叉树A。如下图 所示


我们从第 4 (完全二叉树共8个节点,第8个节点的父节点为 ,所以从4处开始调整 个节点开始调整。此时 A[4] > A[8],于是将两者位置对换。如下图B所示


此时从第3个节点 节点65 ) 开始调整,65 和它的两个孩子比较,发现13较小,于是将13 与 65 对换。如下图 所示。


3个节点比较完之后,我们往回退,从第2个节点开始调整。此时第2个节点比孩子节点都小,故不作调整。

于是又回退,从第1个节点开始进行调整。第1个节点与两个孩子比较,发现右孩子较小,于是将13与 49 进行对换。如下图 所示。


对换之后,49又比它的孩子节点27 大,于是又需要调整。如下图E所示。至此整个调整完成,图E即所要求的小堆的特性。


建小根堆代码

//调整小根堆,从节点i 开始调整   
//存放到数组中的节点是从1开始的void min_heapify(int *a, int i , int len){    int smaller = i;    int l = i << 1;    int r = i <<1 | 1;    if( l <= len && a[l] < a[smaller])        smaller = l ;    if( r <= len && a[r] < a[smaller] )        smaller = r ;    if( smaller != i)  //i节点比孩子节点中至少1个要大,此时需要调整    {        int tmp = a[i];        a[i] = a[smaller];        a[smaller] = tmp;                 min_heapify(a,smaller,len);   //为什么从smaller位置开始调整? 因为此处的值进行了与其父节点互换                                     //所以这个位置可能破坏了堆的特性,需要重新调整,而smaller的兄弟节点没有动,故其堆特性没有发生变化,不需要调整    }}
//建立小根堆void build_min_heap(int *a , int len){    for( int i = len/2 ; i >=1; i--)        min_heapify( a , i,len );}

堆排序算法

堆排序演示

堆排序我们以小根堆来进行排序。我们知道小根堆中的非叶子节点总是比它的孩子节点要小。当我们建立了一个小根堆之后,只需要取出根节点,该根节点也就是待排序序列的第一个元素了。此时将根节点与小根堆中最后一个元素A[n]互换,此时A[n]元素成了根节点,必然破换小根堆的特性,于是需要对小根堆进行调整了。调整完之后,新的小根堆的根节点就是新小根堆的最小元素了,于是又与小根堆的A[n-1]互换,以此循环下去,直到只剩2个节点。


堆排序算法的伪码如下

HEAPSORT ( A)BUILD-MIN-HEAP(A)for i ← length [ A ]  downto 2do  exchange  A [ 1 ] -- A [ i ]    heap-size [ A ] ← heap-size [ A ]-1    MIN-HEAPIFY ( A )

堆排序代码

//堆排序void heap_sort(int *a , int len){    build_min_heap(a, len);    for(int i = len ; i >= 2; i--)    {        cout << a[1] << ' ';        a[1] = a[i];        min_heapify(a,1,i-1);    }    cout << a[1] << endl;}


演示代码

PS:只要将上述代码合并到一起并添加相应的头文件即可运行

int main(){    int a[9] = {0,49,38,65,97,76,13,27,49};    build_min_heap(a,8);
    cout << "建堆 :" << endl;    for(int i = 1; i <=8; i++)        cout << a[i] << ' ';    cout << endl;    cout << "堆排序 :" << endl;    heap_sort(a,8);    cout << endl;    return 0;}




原创粉丝点击