堆的概念
堆是一顆順序儲存的完全二叉樹
每個結點的關鍵字都不大於其孩子結點的關鍵字,這樣的堆稱為小根堆
每個結點的關鍵字都不小於其孩子結點的關鍵字,這樣的堆稱為大根堆
對於n個元素的序列當且僅當下列關係之一的時候,稱之為堆
(1) ri <= r2i + 1 且 ri <= r2i + 2 (小根堆)
(2) ri >= r2i + 1 且 ri >= r2i + 2 (大根堆)
上圖,序列r是個典型的小根堆。
堆中的兩個父結點3和8.
元素3在陣列中以r[0]表示,它的左孩子結點是r[1],右孩子結點是r[2]。
元素8在陣列中以r[1]表示,它的左孩子結點是r[3], 右孩子結點是r[4],父結點是r[0]。他們滿足一下規律
設當前元素在陣列中以r[i]表示,那麼
(1) 它的左孩子是r[2*i+1]
(2) 它的右孩子是r[2*i+2]
(3)它的父結點是r[(i-1)/2]
重要的點:
首先,按堆的定義將陣列r[0..n]調整為堆(這個過程稱為建立初始堆),交換r[0]和r[n];
然後,將r[0..n-1]調整為堆,交換r[0]和r[n-1];
如此反覆,直到交換了r[0]和r[1]為止。
以上思想可歸納為兩個操作:
(1)根據初始陣列去構造初始堆(構建乙個完全二叉樹,保證所有的父結點都比它的孩子結點數值大)。
(2)每次交換第乙個元素跟最後乙個元素,輸出最後乙個元素(最大值),然後把剩下元素重新調整為大根堆。
當輸出完最後乙個元素後,這個陣列已經是按照從小到大的順序排列了。
先通過詳細的例項圖來看一下,如何構建初始堆。
設有乙個無序序列 。
構造了初始堆後,我們來看一下完整的堆排序處理:
還是針對前面提到的無序序列 來加以說明。
//如果父結點的值已經大於孩子結點的值,則直接結束
if (temp >= a[child])
a[parent] = a[child];
parent = child;
child = child * 2 + 1;
}a[parent] = temp;
}void heapsort(std::vector&a)
for (int i = a.size() - 1; i > 0; i--)
}int main()
時間複雜度:堆的儲存表示是順序的。因為堆所對應的二叉樹為完全二叉樹,而完全二叉樹通常採用順序儲存方式。
當想得到乙個序列中第k個最小的元素之前的部分排序序列,最好採用堆排序。
堆排序的時間複雜度是o(n*logn)
演算法穩定性:
堆排序是一種不穩定的排序方法。
因為在堆的調整過程中,關鍵字進行比較和交換所走的是該結點到葉子結點的一條路徑,
因此對於相同的關鍵字就可能出現排在後面的關鍵字被交換到前面來的情況
堆排序(大頂堆)
ifndef maxheap define maxheap includeusing namespace std const int capacity 100 class maxheap void push const int data void initialize int a,int thesi...
堆排序之 大頂堆
堆的定義 設有n個元素的序列 1 2 解釋 如果讓滿足以上條件的元素序列 建堆的步驟 從最後乙個非終端結點開始往前逐步調整,讓每個雙親大於 或小於 子女,直到根節點為止。注意 終端結點 即葉子 沒有任何子女,無需單獨調整。建堆的具體做法 1 將原始序列轉換成完全二叉樹。2 從序號最大的非葉子節點開始...
排序 堆排序 大根堆 大頂堆
1.小根堆 若根節點存在左子女則根節點的值小於左子女的值 若根節點存在右子女則根節點的值小於右子女的值。2.大根堆 若根節點存在左子女則根節點的值大於左子女的值 若根節點存在右子女則根節點的值大於右子女的值。3.結論 1 堆是一棵完全二叉樹 如果公有h層,那麼1 h 1層均滿,在h層連續缺失若干個右...