标签:c style class blog code java
堆是一个完全二叉树,树中每个结点对应于原始数据的一个记录,并且每个结点应满足以下条件:非叶结点的数据大于或等于其左、右孩子结点的数据(若是按从大到小的顺序排序,则要求非叶结点的数据小于或等于其左、右孩子结点的数据)。
由堆的定义可看出,其根结点为最大值,堆排序就是利用这一特点进行的。堆排序过程包括两个阶段:
(1)将无序的数据构成堆(即用无序数据生成满足堆定义的完全二叉树)。
(2)利用堆排序(即用上一步生成的堆输出有序的数据)。
加入有一组要排序的数据:69,65,90,37,92,6,28,54
1.首先,根据堆的定义,将这组数据生成堆
a. 从最后一个非叶节点37开始,比较其子节点,若发现左右节点中有一个比该节点大,则将两个节点进行交换
b. 按照上面的步骤,一遍下来可以将树中最大的节点92筛选到最上面的根节点
2.利用堆进行排序
a. 因为上面排序一遍过后,最大的节点在根节点,因此将根节点与最后一个节点交换,使最大的节点排在最后
b. 由于根节点和最后一个节点交换,破坏了原来的堆结构,所以需要对除了最后一个节点外的其他n-1个节点重新生成堆
c. 重复上面两个步骤,最后剩下的一个节点即为最小节点,排在整个二叉树的根节点,至此则生成从小到大的有序堆
具体图示如下:
(图中输出,即表示为调整到数组最后)
下面贴上具体代码(C语言版):
1 #include <stdio.h> 2 #include "CreateData.c" //生成随机数文件 3 4 #define MAXSIZE 10 5 6 //对指定的节点构成堆 7 //int m 指定的节点 8 //int n 数组的元素个数 9 void HeapAdjust(int a[],int m,int n){ 10 int i,j,t; 11 12 while(2*m+1 < n){ //指定的节点有左子树 13 j = 2*m+1; //m的左子树 14 15 if(j+1 < n){ 16 //有右子树,且右子树大于左子树 17 if(a[j] < a[j+1]) j++; 18 } 19 20 21 if(a[m] < a[j]){ 22 //如果有个子树大于根节点,则交换 23 t = a[m]; 24 a[m] = a[j]; 25 a[j] = t; 26 27 m = j; //交换过以后,以j为根的节点再重新生成堆 28 }else 29 break; 30 31 } 32 } 33 34 //堆排序算法 35 void HeapSort(int a[],int n){ 36 int i,t; 37 38 i = n/2-1; 39 40 for(;i>=0;i--) 41 HeapAdjust(a,i,n); 42 43 for(i = n-1;i>=0;i--){ 44 //将树根节点(最大)放到最后一个元素 45 t = a[i]; 46 a[i] = a[0]; 47 a[0] = t; 48 49 //破坏了根节点,再对根节点重新生成堆 50 HeapAdjust(a,0,i); 51 } 52 } 53 54 int main(){ 55 int a[MAXSIZE]; 56 int i; 57 58 59 if(!CreateData(a,100,10,MAXSIZE)){ 60 printf("生成随机数失败.\n"); 61 return 0; 62 } 63 64 printf("排序前:"); 65 for(i = 0 ; i < MAXSIZE ;i++) 66 printf("%d ",a[i]); 67 68 HeapSort(a,MAXSIZE); 69 70 printf("\n排序后:"); 71 for(i = 0 ; i < MAXSIZE ;i++) 72 printf("%d ",a[i]); 73 printf("\n"); 74 75 return 1; 76 }
此段代码在调试的过程中比较坎坷,在Linux中有时候会发现比较古怪的问题,比如陷入死循环但是很难追踪,不过都是个人粗心,有几个变量赋值和循环条件刚开始的时候写错了。不过现在经测试已经运行稳定,并实现从小到大进行数据排序功能。
标签:c style class blog code java
原文地址:http://www.cnblogs.com/fanchangfa/p/3762625.html