排序算法05------------------------堆排序(圖解)

1.堆排序

  堆排序是用堆這種數據結構所設計的一種排序算法,近似一顆完成二叉樹,同時具有一個特性,父節點的值大於(小於)子節點的值。

堆分兩種,父節點比子節點大的叫最大堆,父節點比子節點小的叫最小堆

下面就是一個最大堆

 

 2.堆排序步驟

以最大堆爲例,假設有n個元素,

1)構造最大堆

2)交換根節點與第n個節點的值

3)將當前的堆調整爲最大堆

4)n減一,繼續2)3)步驟,直到n==1

3.如何構造最大堆

  由最大堆的性質可知,每個父節點的值都比子節點的值大,所以要從下往上調整,調整後根節點就是最大的。舉個例子

假設數組array :   

 

 1)先把它想象成下面的形式(完全二叉樹),在數組中還是按順序排序的,

 

 2)開始構造最大堆

  1.先找到最後一個父節點,由於最大堆的形式是上面的形式,所以很容易得到最後一個父節點的下標,上面的元素是8個

  那麼最後父節點的下標:i=8/2-1=3,而且該節點的左子節點的下標是:2i+1,右子節點下標是:2i+2 這是很重要的性質。

  比較i和2i+1,2i+2的對應值,如果這兩個子節點比父節點大,那麼就交換父子節點的值,要注意要判斷2i+1和2i+2存不存在(即下標不能越界)

 

   第一次調整後:

          

 

   第二次:

  

 

 

 

  第三次

  

 

 

 

  第四次

  

 

 

 

  這時,要注意交換後可能導致後面的節點不滿足最大堆的性質,此時繼續按照上面的步驟來,其實就是一個遞歸,等下看代碼就好理解了

  第五次,調整完成

  

 

 

  開始交換

3)交換根節點與第 n-i(i是已經交換的元素個數)個元素的值

 

 

 

4)然後把它調整成一個最大堆,此時要從上往下調整,即從根節點開始調整。

 

 

 5) 繼續 3),4)步驟,直到n-i==1,此時排序完成

 

結合代碼過一遍就很容易懂了

代碼如下:

 1 #include<stdio.h>
 2 //交換兩個數的值 
 3 void swap(int *a,int * b)
 4 {
 5     int temp=*a;
 6     *a=*b;
 7     *b=temp;
 8 }
 9 //構造最大堆過程 
10 void maxHead(int *arr,int start,int end)
11 {
12     int parentNode=start;//父節點 
13     int childNode=parentNode*2+1;//左子節點
14     while(childNode<=end)
15     {    
16         //childNode+1是右子節點 
17         if(childNode+1<=end&&arr[childNode+1]>arr[childNode])
18             childNode++;//右子節點大,取右子節點
19         //父節點比子節點大,不用交換,直接返回 
20         if(arr[parentNode]>arr[childNode])
21             return;
22         //否則,交換父節點與子節點的值 
23         else
24         {    
25             swap(&arr[parentNode],&arr[childNode]);
26             
27             //交換後有可能導致後面的節點
28             //不滿足最大堆的要求,所以繼續對後面的節點進行構造
29             parentNode=childNode;
30             childNode=parentNode*2+1;
31         } 
32     } 
33         
34 }
35 void headSort(int * arr,int num)
36 {    
37     //num數組元素個數 
38     int i;
39     //一開始先構造一個最大堆 
40     for(i=num/2-1;i>=0;i--)
41         maxHead(arr,i,num-1);
42      
43     for(i=num-1;i>0;i--)
44     {
45         swap(&arr[i],&arr[0]);//交換第一個元素與第i(i從後面開始)個元素
46         maxHead(arr,0,i-1);//交換後繼續進行構造最大堆操作 
47     } 
48 }
49 int main()
50 {
51     int i; 
52     int arr[8]={1,5,0,6,3,9,8,7};
53     headSort(arr,8);//堆排序 
54     for(i=0;i<8;i++)
55         printf("%d\n",arr[i]);
56     return 0;
57 } 

堆排序的平均時間複雜度是:O(nlogn)

有問題,隨時聯繫

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章