一、定義
二叉堆是堆的一種,使用完全二叉樹來實現。所謂完全二叉樹,即高度為n的二叉樹,其前n-1層必須被填滿,第n層也要從左到右順序填滿。在二叉堆中,所有非終端結點的值均不大於(或不小於)其左右孩子的值。若非終端結點的值均不大於其左右孩子結點的值,這樣的二叉堆叫做小根堆(下圖中(b)),小根堆根結點的值是該堆中所有結點的最小值;同樣的,當所有非終端結點的值都不小於其左右孩子的值時,這樣的對叫做大根堆(下圖中(a)),大根堆根結點的值為改堆所有結點的最大值。利用堆的此性質,可以實現堆排序。
說明:小根堆和大根堆的實現沒有太大的區別,所以下面以小根堆為例。
二、二叉堆的操作
堆一般使用數組來構建,假設為數組a[],結點通常存儲在a[1],這樣對於下標為k的結點a[k]來說,其左孩子的下標為2*k,右孩子的下標為2*k+1。
1、插入結點到堆中.
由於小根堆是由數組實現的完全二叉樹,所以插入的位置應該是完全二叉樹的最后一個位置(如下圖所示),對於小根堆來講,需要滿足兩個性質:(1)堆為完全二叉樹;(2)堆中每個結點的值都不大於其左右結點的值。插入結點可能會破壞這兩條性質,所以在插入結點后需要對堆進行調整。調整方法為:將插入的結點與其父結點比較,若小於其父結點的值,則交換兩者。重復此操作,直至該結點不比其父結點小,或者該結點成為根結點。可以通過插入結點到一個已經存在的堆中,也可以通過不斷插入結點來構建一個堆。
2、刪除堆頂元素(堆排序)
刪除堆頂元素(根結點)后,會得到左右兩棵子樹,此時將堆中最后一個元素移到堆頂,然后自上而下調整,將該結點與左右孩子結點比較,此時會有三種情況:
(1)結點的左右孩子均為空,此時調整結束;
(2)結點只有左孩子,此時將該結點與其左孩子比較。若結點大於其左孩子,則兩者交換,否則調整結束;
(3)結點左右孩子都非空,則將該結點與左右孩子之間的較小者比較,若小於則交換,否則調整結束;
重復此過程,直到該結點不大於其左右孩子結點,或者該結點為葉子結點。
3、實現代碼
#include <algorithm> #include <iostream> using namespace std; class MinHeap { private: int* heap; //存儲堆 int cur; //堆中結點個數 /*插入結點后,向上調整*/ void adjustUp(); /*刪除結點后,向下調整*/ void adjustDown(int idx); public: MinHeap(); ~MinHeap(); /*插入值為val的結點*/ void insert(int val); /*返回最小值並刪除最小值結點*/ int deleteMin(); }; MinHeap::MinHeap() { heap = new int[20]; cur = 0; } MinHeap::~MinHeap() { delete[] heap; } /*插入值為val的結點*/ void MinHeap::insert(int val) { heap[++cur] = val; adjustUp(); } /*插入結點后,向上調整*/ void MinHeap::adjustUp() { int idx = cur; int pIdx = cur / 2; while (pIdx > 0 && heap[idx] < heap[pIdx]) { swap(heap[idx], heap[pIdx]); idx = pIdx; pIdx = pIdx / 2; } } /*返回最小值並刪除最小值結點*/ int MinHeap::deleteMin() { int minVal = heap[1]; heap[1] = heap[cur--]; adjustDown(1); return minVal; } /*刪除結點后,向下調整*/ void MinHeap::adjustDown(int idx) { if (idx > cur) return; int lIdx = idx * 2; int rIdx = idx * 2 + 1; int minIdx = 0; if (lIdx > cur) //無左右孩子 return; else if (rIdx > cur) //只有左孩子 minIdx = lIdx; else minIdx = heap[lIdx] < heap[rIdx] ? lIdx : rIdx; //左右孩子均非空 if (heap[idx] > heap[minIdx]) { swap(heap[idx], heap[minIdx]); adjustDown(minIdx); } else return; } int main() { int a[] = { 5,1,3,4,2 }; int len = sizeof(a) / sizeof(a[0]); /*插入結點構造最小堆*/ MinHeap* minHeap = new MinHeap(); for (int i = 0;i < len; i++) minHeap->insert(a[i]); /*輸出堆頂結點的值*/ for (int i = 0;i < len;i++) cout << minHeap->deleteMin() << " "; cout << endl; return 0; }
結果:
1 2 3 4 5
三、參考
1、http://www.cnblogs.com/vamei/archive/2013/03/20/2966612.html
2、嚴蔚敏、吳偉民《數據結構》