堆(二叉堆)是一種用於實現優先隊列模型的數據結構,堆具備堆序(heap order)性,每一個節點的關鍵字都大於他的父節點的
只有根除外(沒有父親),也能夠是都小於,子節點與父節點的關係決定了這個堆是最小堆仍是最大堆,分別能夠用來作升序和降序。使用優先隊列理論上能夠實現花費O(N log N)時間的排序。數組
對一個數組進行升序的排列,能夠先將數組中的N個元素創建一個二叉堆,這個操做花費O(N)時間,而後對該堆執行N此DeleteMin操做。堆中的數據按照從小到大依次離開堆,將這些元素記錄到第二個數組中,最後再拷貝回來,以此獲得了針對N個元素的排序。每一個DeleteMin操做花費了O(log N)的時間,所以總開銷是O(N log N)。
注意到咱們這裏使用了一個額外的數組,空間開銷加大了(將第二個數組數據拷貝回來只花費O(N),不會顯著增長時間消耗)。
雖然咱們在程序中經常爲了節省時間開銷而消耗額外的空間,但在這個問題中有個方法能夠避免。在每次DeleteMin操做以後,堆縮小了1,,所以堆中最後的單元能夠用來存放剛剛刪去的元素。數據結構
這是在排序中重點須要的基本堆操做,要找到須要刪除的元素很容易,難的是刪除,當刪除一個最小元時,在根節點產生了一個空穴,爲了保證堆的性質,必需將堆中最後一個元素X移動,若是它能夠移動到空穴,那麼DeleteMin完成,不過這通常不太可能,所以咱們將空穴的兩個子節點中較小的一個移入空穴,至關於把空穴往下移動了一層,不斷重複這個過程直到X能夠被放到空穴。這種策略被稱做下濾。
最小堆與最大堆具備對稱的性質,對於父節點大於子節點的最大堆,區別只是每次刪除的是最大元,上移的是空穴子節點中較大的,與最小堆相反。spa
#define LeftChild(i) (2 * (i) + 1) void PercDown(ElementType A[], int i, int N) { int Child; ElementType Tmp; for (Tmp = A[i]; LeftChild(i) < N; i = Child) { Child = LeftChild(i); if (Child != N - 1 && A[Child + 1] > A[Child]) Child++; if (Tmp < A[Child]) A[i] = A[Child]; else break; } A[i] = Tmp; } void Heapsort(ElementType A[], int N) { int i; for (i = N / 2; i >= 0; i--) PercDown(A, i, N); for (i = N - 1; i > 0; i--) { Swap(&A[0], &A[i]); PercDown(A, 0, i); } }