堆結構是一種數組對象,其定義如下:它是完全二叉樹或者近似完全二叉樹。經常作為優先順序隊列,比如二叉樹優先順序隊列,四叉樹優先順序隊列。
n個關鍵字序列Kl,K2,…,Kn稱為(Heap),若且唯若該序列滿足如下性質(簡稱為堆性質):
(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),當然,這是小根堆,大根堆則換成>=號。
k(i)相當於二叉樹的非葉結點,K(2i)則是左孩子,k(2i+1)是右孩子
若將此序列所儲存的向量R[1..n]看做是一棵完全二叉樹的儲存結構,則堆實質上是滿足如下性質的完全二叉樹:
樹中任一非葉結點的關鍵字均不大於(或不小於)其左右孩子(若存在)結點的關鍵字。
優先順序隊列是不同於先進先出隊列的另一種隊列。
最大優先順序隊列,是這樣的一種隊列結構,它的內部存放著一系列的元素,每個元素都對應著一個最優級,
最大優先順序隊列不管各元素的入隊順序,在出隊時,總是對應優先順序最大的元素出隊。
最小優先順序隊列正好相反,不管入隊的順序,對應的權值最小的隊列元素出隊列。
優先順序隊列可以用二叉樹來實現,比如最大元素出隊列,只要在二叉樹中用常數時間取出最大值就可以了。取出了最大值之後,要繼續調整樹的狀態,使得第二大節點放入根節點。
堆排序
基本思想:對一組待排序記錄的關鍵字,首先建立一個堆,然後輸出最大(小)關鍵字,使得其餘的關鍵字重新構成一個堆,得到次大(小)的元素。這樣反覆執行,使得記錄成為一個有序序列,這個過程就稱為堆排序。由此可見,堆排序主要解決兩個問題:(1)如何使得一個無序的序列稱為一個有序的序列;(2)如何在輸出對頂元素之後,調整剩餘元素使之稱為一個堆。
調整堆的過程:從非終端節點開始,一直到最後節點。
//調整堆使之稱為大(小)頂堆void HeapAdjust(int *data,int s,int m){int j;int rc = data[s];for (j = 2 * s; j < m; j *= 2)//沿著關鍵字較大的孩子節點向下篩選{if (j < m && data[j] < data[j+1]){++j;//j是值較大元素的下標}if (!(rc<data[j])){break;}data[s] = data[j];s = j;//rc應插入在位置s上}data[s] = rc; //插入}
而建立堆只要從最後一個非葉子節點開始,向前逐步調整,這種調整的方法常稱為“篩選法”。
//堆排序void Heap_Sort(int* a,int n){int i = 0;for (i=n/2; i>0; i--)//把a建成大頂堆{HeapAdjust(a,i,n-1);}int temp;//臨時變數for (i=n-1; i>0; i--) //將當前節點和最後一個資料交換{temp = a[0];a[0] = a[i];a[i] = temp;HeapAdjust(a,0,i-1);}}
堆排序的優點:平均時間複雜度是最壞時間複雜度都是O(nlogn),效率比較高。僅僅需要一個供交換用的輔助記錄大小空間。
缺點:不穩定,相同的資料元素在排序過程中可能移動位置。對於記錄數較少的排序不適合。