1、认识大顶堆和小顶堆
(1)大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列。
(2)小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列。
2、基本思想:先把数组构造成一个大顶堆(父亲节点大于其子节点),然后把堆顶(数组最大值,
数组第一个元素)和数组最后一个元素交换,这样就把最大值放到了数组最后边。把数组长度n-1,
再进行构造堆,把剩余的第二大值放到堆顶,输出堆顶(放到剩余未排序数组最后面)。依次类推,直
至数组排序完成。
3、对一个堆来说,要符合以下两个特点
(1)是一个完全二叉树。
(2)所有父节点的值都要大于(或等于)其子节点的值。
4、堆的重建
(1)移出完全二叉树根节点中的记录,该记录称为待调整记录,此时的根节点接近于空节点。
(2)从空节点的左、右孩子中选出一个关键字较小的记录,如果该记录的关键字小于待调整记录
的关键字,则将该记录上移至空节点中。此时,原来那个关键字较小的子节点相当于空节点。
(3)重复上述移动步骤,直到空节点左、右孩子的关键字均不小于待调整记录的关键字为止,此
时将待调整记录放入空节点即可完成重建。通过上述调整方法,实际上是把待调整记录实现了逐步
向下处理,所以上述过程一般被称为“筛选”法。
5、堆排序的具体步骤
(1)将待排序记录按照堆的定义建立一个初堆,并输出堆顶元素。
(2)调整剩余的记录序列,使用筛选法将前n-i个元素重新筛选,以便建成为一个新堆,然后再输
出堆顶元素。
(3)重复执行步骤(2),实现n-1次筛选,这样新筛选成的堆会越来越小,而新堆后面的有序关键
字会越来越多,最后使待排序记录序列成为一个有序的序列,这个过程被称为堆排序。
6、代码
#include <stdio.h> #include <time.h> #include <stdlib.h> void HeapSort(int a[],int len); void HeapSort(int a[],int len) //堆排序 { int i,j,temp; while(len > 1) { /从最后一个拥有孩子的节点开始判断,此处不懂的画个图就懂了 for(i = (len/2-1);i >= 0;i--)/ { if(a[i] < a[2*i+2] && (2*i+2)<(len-1))//判断它的右孩子 { temp = a[i]; a[i] = a[2*i+2]; a[2*i+2] = temp; } if(a[i] < a[2*i+1])//判断它的左孩子 { temp = a[i]; a[i] = a[2*i+1]; a[2*i+1] = temp; } } //构成大顶堆后,把第一个元素放到数组后面 temp = a[len-1]; a[len-1] = a[0]; a[0] = temp; len--; } } int main(int argc, char *argv[]) { int a[10] = {0}; int i = 0; srand((unsigned)time(NULL));//随机数 for(i = 0;i < sizeof(a)/sizeof(a[0]);i++) a[i] = rand()%100+1; printf("原始序列为\n"); i = 0; while(i < sizeof(a)/sizeof(a[0])) { printf("%d ",a[i]); i++; } printf("\n"); HeapSort(a,sizeof(a)/sizeof(a[0])); printf("排序后的序列为\n"); i = 0; while(i < sizeof(a)/sizeof(a[0])) { printf("%d ",a[i]); i++; } printf("\n"); return 0; }
7、运行结果
原始序列为 76 58 46 32 22 69 19 28 97 5 排序后的序列为 5 19 22 28 32 46 58 69 76 97
由此可见,完成堆排序。