1. 程式人生 > >隨便說說堆(一)——二叉堆

隨便說說堆(一)——二叉堆

復雜 ges union 最大 輸入 個數 img image 下標

二叉堆可以被看作是一個數組,也可以簡單的看作是一個近似的完全二叉樹,二叉堆有最大堆和最小堆,分別具有堆的性質:最大堆的某個結點的值最多與其父結點一樣大,最小堆則是某個結點的值最多與其父結點一樣小。所以最大堆中最大的結點永遠是根結點,最小堆中最小的結點永遠是根節點。

既然二叉堆是一種數據結構,就有其支持的操作(這裏以最小堆為例):

  • make_heap:建立一個空堆,或者把數組中元素轉換成二叉堆。
  • insert:插入元素。
  • minimun:返回一個最小數。
  • extract_min:移除最小結點。
  • union:合並堆

make_heap

先給一組數{27,17,3,16,13,10,1,5,7}輸入數組,數組下標從0開始。然後我們畫出這棵樹:

技術分享圖片

然後根據近似滿二叉樹的性質,有n個結點,[n/2]+1,[n/2]+2,……,n都是葉結點。然後可以通過對除了葉結點以外的結點i(0到n/2)進行一次下濾的操作,若兒子結點有小於結點i的結點,將兒子結點中最小者與結點i交換,再與交換後的位置的兒子結點繼續比較,直到小於兒子結點或者為葉結點為止。遍歷完,就得到最小堆。 時間復雜度建立空堆O(1),立地建堆O(n)。

圖示

技術分享圖片

代碼實現

 1 //維護堆
 2 void max_heapify(int *a, int i) {
 3     int l = 2 * i + 1;
 4     int r = 2
* i + 2; 5 int largest; 6 if (a[l] != -1 && a[l] < a[i]) largest = l; 7 else largest = i; 8 if (a[r] != -1 && a[r] < a[largest]) largest = r; 9 if (largest != i) { 10 swap(a[i], a[largest]); 11 max_heapify(a, largest); 12 }
13 } 14 //建堆 15 void make_heap(int *a, int n) { 16 for (int i = n / 2; i >= 0; i--) max_heapify(a, i); 17 }


insert

對於插入操作,首先將元素push到數組尾部,然後將其進行上濾操作,也就是將其與父結點比較,如果小於父結點就交換,直到大於等於父結點或者到達根。時間復雜度為O(logn)

舉個例子:在{1,5,3,7,13,10,27,16,17}中插入4。

圖示

技術分享圖片

代碼實現

1 //n是數組長度
2 void insert(int *a, int num, int &n) {
3     a[n++] = num;
4     for (int i = n - 1; i >= 0; i = (i - 1) / 2) {
5         if (a[i] < a[(i - 1) / 2]) swap(a[i], a[(i - 1) / 2]);
6         else break;
7     }
8 }


minimun

返回最小數,對於最小堆來說返回根即可。時間復雜度O(1)

代碼實現

1 int minimun(int *a) {
2     return a[0];
3 }


extract_min

移除最小頂點,也就是最小堆的根,此時需要將堆最後一個葉節點摘下替換掉根,這樣不會破壞近似滿二叉樹的結構,然後從上至下更新堆,維護堆的性質。時間復雜度O(logn)

圖示

技術分享圖片

代碼實現

1 void extract_min(int *a, int &n) {
2     a[0] = a[n - 1];
3     n--;
4     max_heapify(a, 0);
5 }


union

合並堆的話其實就相當於把兩個堆數組合並,然後重新建堆。所以時間復雜度也是線性的,為O(n)。

代碼實現

1 void Union(int *a, int *b, int &n, int &m) {
2     for (int i = 0; i < m; i++) {
3         a[n++] = b[i];
4     }
5     m = 0;
6     memset(b, -1, sizeof(b));
7     for (int i = n / 2; i >= 0; i--) max_heapify(a, i);
8 }

這裏就說完了二叉堆,下一篇在隨便說說堆中的二項堆。

隨便說說堆(一)——二叉堆