#排序算法#【3】堆排序

  堆是一个完全二叉树,树中每个结点对应于原始数据的一个记录,并且每个结点应满足以下条件:非叶结点的数据大于或等于其左、右孩子结点的数据(若是按从大到小的顺序排序,则要求非叶结点的数据小于或等于其左、右孩子结点的数据)。

由堆的定义可看出,其根结点为最大值,堆排序就是利用这一特点进行的。堆排序过程包括两个阶段:

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("生成随机数失败.
");
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("
排序后:");
71     for(i = 0 ; i < MAXSIZE ;i++)
72         printf("%d ",a[i]);
73     printf("
");
74 
75     return 1;
76 }

  此段代码在调试的过程中比较坎坷,在Linux中有时候会发现比较古怪的问题,比如陷入死循环但是很难追踪,不过都是个人粗心,有几个变量赋值和循环条件刚开始的时候写错了。不过现在经测试已经运行稳定,并实现从小到大进行数据排序功能。

原文地址:https://www.cnblogs.com/fanchangfa/p/3762625.html