堆排序算法

来源:互联网 发布:淘宝客定向计划 编辑:程序博客网 时间:2024/06/03 16:46
 

这篇文章主要是日前朋友写过一个堆排序的算法,而我对这一块儿基本上都忘光了,于是翻书,查询网络,重新建立起堆及堆排序的概念

第一部分是从网上查到的一篇关于用C++实现的堆排序的文章,第二部分则是朋友写的堆排序的代码,我调试过,现在算是对堆排序又有了重新的认识。以后说不定用得着,先挂在这儿了。

转载地址: http://www.cppblog.com/bujiwu/archive/2008/10/26/65146.html

1、 堆排序定义
n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
(1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ )

若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。
2、大根堆和小根堆
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆。
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆。
注意:
①堆中任一子树亦是堆。
②以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。
3、堆排序特点
堆排序(HeapSort)是一树形选择排序。
堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系【参见二叉树的顺序存储结构】,在当前无序区中选择关键字最大(或最小)的记录。
4、堆排序与直接插入排序的区别
直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。
5、堆排序
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

 1 /* 2 堆排序 3 (1)用大根堆排序的基本思想 4 ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区 5 ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换, 6 由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key 7 ③ 由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。 8 然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换, 9 由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n- 2].keys≤R[n-1..n].keys,10 同样要将R[1..n-2]调整为堆。11 ……12 直到无序区只有一个元素为止。13 (2)大根堆排序算法的基本操作:14 ① 初始化操作:将R[1..n]构造为初始堆;15 ② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。16 注意:17 ①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。18 ②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。19 堆排序和直接选择排序相反:在任何时刻,堆排序中无序区总是在有序区之前,20 且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。 21 */22 23 //生成大根堆24 void HeapAdjust(int SortData[],int StartIndex, int Length)25 {26     while(2*StartIndex+1 < Length)27     {28         int MinChildrenIndex = 2*StartIndex+1 ;29         if(2*StartIndex+2 < Length )30         {31             //比较左子树和右子树,记录最大值的Index32             if(SortData[2*StartIndex+1]<SortData[2*StartIndex+2])33             {34                 MinChildrenIndex = 2*StartIndex+2;35             }36         }37         if(SortData[StartIndex] < SortData[MinChildrenIndex])38         {39             //交换i与MinChildrenIndex的数据40             int tmpData =SortData[StartIndex];41             SortData[StartIndex] =SortData[MinChildrenIndex];42             SortData[MinChildrenIndex] =tmpData;43             //堆被破坏,需要重新调整44             StartIndex = MinChildrenIndex ;45         }46         else47         {48             //比较左右孩子均大则堆未破坏,不再需要调整49             break;50         }51     }52 53     return;54 }55 56 //堆排序57 void HeapSortData(int SortData[], int Length)58 {59     int i=0;60 61     //将Hr[0,Lenght-1]建成大根堆62     for (i=Length/2-1; i>=0; i--)63     {64         HeapAdjust(SortData, i, Length);65     }66 67     for (i=Length-1; i>0; i--)68     {69         //与最后一个记录交换70         int tmpData =SortData[0];71         SortData[0] =SortData[i];72         SortData[i] =tmpData;73         //将H.r[0..i]重新调整为大根堆74         HeapAdjust(SortData, 0, i);75     }76   77     return;78 }


下半部分是朋友写的堆排序的代码,方便日后查询

#include <stdio.h>#define ARRAY_SIZE(ary) (sizeof(ary) / sizeof((ary)[0]))#define PRINT_ARY(ary, size) do {            \    int i = 0;                        \    for (; i < size; ++i)             \        printf("%d ", ary[i]);    \    puts("");                         \} while (0)#define PARENT(i) ((i) / 2)#define LEFT(i) (2 * (i))#define RIGHT(i) (LEFT(i) + 1)typedef struct _HEAP{    int    *a;    int nSize;}HEAP;#define HEAP_SIZE(pHeap) (((HEAP*)(pHeap))->nSize)void swap(int *p, int *q){    int t = *p;    *p = *q;    *q = t;}void max_heapipy(HEAP *pHeap, int nPos){    int l = LEFT(nPos);    int r = RIGHT(nPos);    int nLargest;    if (l < HEAP_SIZE(pHeap) && pHeap->a[l] > pHeap->a[nPos])    {        nLargest = l;    }    else    {        nLargest = nPos;    }    if (r < HEAP_SIZE(pHeap) && pHeap->a[r] > pHeap->a[nLargest])    {        nLargest = r;    }    if (nLargest != nPos)    {        swap(pHeap->a + nPos, pHeap->a + nLargest);        max_heapipy(pHeap, nLargest);    }}void build_heap(HEAP *pHeap){    int i;    for (i = HEAP_SIZE(pHeap) / 2 - 1; i > -1; --i)    {        max_heapipy(pHeap, i);    }}void heap_sort(HEAP *pHeap){    int i;    int nHeapSize = HEAP_SIZE(pHeap);//pHeap->nSize;    build_heap(pHeap);    PRINT_ARY(pHeap->a, pHeap->nSize);    for (i = nHeapSize - 1; i > 0; )    {        swap(pHeap->a, pHeap->a + i);        i = --HEAP_SIZE(pHeap) - 1;        max_heapipy(pHeap, 0);    }    pHeap->nSize = nHeapSize;}int main(int argc, char *argv[]){    //int ary[] = { 1, 4, 2, 8, 14, 16, 9, 7, 3, 10 };    //int ary[] = { 5, 13, 2, 25, 7, 17, 20, 8, 4 };    int ary[] = { 15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1 };    HEAP heap = {ary,  0};    heap.nSize = ARRAY_SIZE(ary);    PRINT_ARY(heap.a, heap.nSize);    heap_sort(&heap);    PRINT_ARY(heap.a, heap.nSize);    return 0;}


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 头孢和藿香正气水一起吃了怎么办 小儿胃蛋自酶合剂吃多了怎么办 刚出生的婴儿很容易被惊醒怎么办 1个多月的宝宝小腿不直怎么办 20个月宝宝腿不直小腿外八怎么办 小孩手青枝骨骨折拆石膏还弯怎么办 宝宝喝柴胡注射剂有不良反应怎么办 九个月宝宝便秘拉不出来怎么办 一岁四个月的宝宝便秘怎么办 热血三国3要塞打不过去怎么办 清香木夏天有黄叶和掉叶怎么办 生完宝宝妊娠纹还在继续疯长怎么办 陌陌不能最小化观看直播视频怎么办 苏州园区公积金密码忘记了怎么办 房产企业申请破产买的房子怎么办 被业务员骗了买了保险怎么办 孩子特别害怕老师严厉的批评怎么办 4k电视看有线电视不清晰怎么办 移动9.9流量4g网用完了怎么办 东方头条验证码已经被注册了怎么办 打王者两个人吵架被夹在中间怎么办 顾客拿过期的食品过来投诉怎么办 老婆总是埋怨我父母我该怎么办? 代款公司如果使用暴力追债怎么办 法院拍卖款分配有疑意怎么办 法院拍卖买到的房子里有户口怎么办 新注册手机邮箱不和电脑同步怎么办 移动4g盒当月流量封顶怎么办 昆仑加油卡密码忘记了怎么办 昆仑银行e盾密码忘记了怎么办 中石化加油卡密码忘记了怎么办 壳牌加油卡密码忘了怎么办 中国石化加油卡密码忘了怎么办 中石化加油卡密码忘了怎么办 中石化加油卡需要密码忘了怎么办 求不熟领导办事送礼不收怎么办 送礼给领导不收好像很生气怎么办 加油卡没有密码加油后锁住怎么办 个人怎么办中石化油卡怎么开公司票 中石化副卡挂失后钱怎么办 中石化的加油卡丢了怎么办