最大(小)堆和堆排序簡介


(注:本文的相關敘述和圖片摘自《數據結構與算法分析新視角》(周幸妮等),因此本文只是我的一個復習記錄,詳細的論述請參考該書。)

1. 最大(小)堆

  對於一個完全二叉樹來說,如果所有的結點(葉子結點除外)的值都大於(小於)其左右孩子結點的值,那么這個完全二叉樹就被成為一個大(小)根堆。如下圖所示。按照堆的定義可以發現,堆頂結點(二叉樹的根結點)一定對應整個序列中的最大(小)記錄。這樣一來,可以設計一種排序思路,每次將堆的堆頂記錄輸出,同時調整剩余的記錄,使它們從新排成一個堆。重復這個過程,就能最終得到一個有序的序列,完成排序的過程,這種方法稱之為堆排序。

  因此,對於堆排序來說,主要有兩個問題:

  • 一個無序序列的所有記錄如何排列成一個堆?
  • 在輸出了堆頂記錄后,如何將剩下的記錄再排成一個堆?

2. 堆排序

  • 由無序序列生成堆

  以序列{49,38,65,97,76,13,27,49,55,04}為例,介紹生成最小堆的思路。我們知道一棵完全二叉樹的最后一個非葉子結點的索引為[n/2],因此在本例中,選擇第5個記錄{76}作為初始篩選點。首先比較{76}與其左右孩子結點記錄的大小,並按照篩選的結果進行交換,因此得到下圖2的結果。接下來對倒數第二個非葉子結點進行處理,結果如下圖3所示。重復這個步驟,可以得到一個結構完整的最小堆,如下圖4所示。

            

                                          (1)序列直接構成完全二叉樹       (2)一次篩選之后的完全二叉樹      (3)二次篩選之后的完全二叉樹

 

(4)經過多次篩選之后的最小堆

  • 堆排序

  以序列{13,38,27,49,76,65,49,97}為例,介紹堆排序的思路。

                              初始堆                                              輸出堆頂元素后的情形

                   最后一個記錄暫放於堆頂                                      一次調整之后的情形

                      二次調整之后的情況                                輸出記錄{27}之后再排成一個堆

   重復上述步驟,最終就可以生成一個有序序列。

 3. 相關代碼

  • 生成最大堆代碼(最小堆類似)
 1 //調整堆結點 
2
//arr:數組首地址;n:結點在數組中的位置;len:數組的長度 3 void adjust_node(int *arr, int n, int len) 4 { 5 int l, r, max, tmp; 6 l = 2 * n + 1; //左右孩子的索引,注意數組下標從0開始。 7 r = 2 * n + 2; 8 max = n; 9 10 if (l<len&&arr[l]>arr[n]) 11 max = l; 12 if (r<len&&arr[r]>arr[max]) 13 max = r; 14 15 if (max != n) 16 { 17 tmp = arr[n]; 18 arr[n] = arr[max]; 19 arr[max] = tmp; 20 adjust_node(arr, max, len); //保證最大堆 21 } 22 }
  • 堆排序
 1 //堆排序(升序)
 2 void sort_heap(int *arr, int len)
 3 {
 4     for (int i = len / 2; i >= 0; i--)
 5         adjust_node(arr, i, len);
 6     int tmp;
 7     for (int i = len - 1; i >= 0; i--)
 8     {
 9         tmp = arr[0];
10         arr[0] = arr[i];
11         arr[i] = tmp;
12         adjust_node(arr, 0, i);
13     }
14 }
  • 驗證
 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int arr[] = { 49,38,65,97,76,13,27,49,55,04 };
 7     int len = 10;
 8 
 9     for (int i = 0; i < len; i++)
10         cout << arr[i] << ' ';
11     cout << endl;
12 
15     sort_heap(arr, len);
16 
17     for (int i = 0; i < len; i++)
18         cout << arr[i] << ' ';
19     cout << endl;
20 
21     return 0;    
22 }

輸出結果:

49 38 65 97 76 13 27 49 55 4
4 13 27 38 49 49 55 65 76 97


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM