(二叉)堆是乙個陣列,可以看成為乙個近似的完全二叉樹。樹上的每乙個節點對應陣列中的乙個元素,除了最底層外,其他層是完全充滿的,而且是從左到右填充。表示堆的陣列a包括兩個屬性,a.length表示陣列元素的個數,a.heapsize表示有多少個堆元素儲存在該陣列中。
樹的根節點是a[1],給定乙個節點的下標i,可以得到它的父節點,左孩子和右孩子下標:
//父節點,下標向下取整
intparent
(int i)
//左孩子節點
intleft
(int i)
//右孩子節點
intright
(int i)
二叉堆可以分成兩種形式:最大堆和最小堆。在最大堆中,除了根節點之外的所有節點 i 都要滿足a[parent(i)] >= a[i],也就是說某個節點的值至多和其父節點一樣大。在最小堆中正好相反。
堆的性質:1.高度為h的堆中,元素個數最少為2^(n), 最多為2^(n+1)-1;
2.含有n個元素的堆的高度為lgn(以2為底)向下取整。
3.當用陣列表示儲存n個元素的堆時,葉子節點的下標分別為(n/2+1),(n/2+2),…,n(均為向下取整)。因為,最後乙個節點的父節點為(n/2),其後所有節點均為葉子節點。
維護堆的性質
maxheapify用於維護堆的性質,通過讓a[i]同左右孩子對比,使得小值在最大堆中逐級下降。
void
maxheapify
(int a,
int heapsize,
int i)
}
在交換後,下標為largest的節點的值時原來的a[i],以其為根節點的子樹可能會違反最大堆的性質,需要還需遞迴呼叫。這個函式的事件複雜度為o(lg n),根據堆性質,對於乙個樹高為h的節點來說,時間複雜度為o(h)。
建堆
自底向上建堆。
void
buildmaxheap
(int a,
int heapsize)
下標 i 從最後乙個根節點開始,也就是(heapsize/2)。自底向上建堆是為了保證以當前節點 i 的左右孩子為根節點的子樹是最大堆。
堆排序
時間複雜度為o(n * lg n)
void
heapsort
(int a,
int heapsize)
}
將 a[1] 同 a[heapsize] 交換,在將heapsize減一,然後調整到最大堆。
優先佇列
優先佇列:一種用來維護由一組元素構成的集合s的資料結構,其中的每乙個元素都有乙個相關的值,稱為關鍵字,最大優先佇列操作包括:
insert(a,x):把元素插入到集合a中;
maximum(a):返回a中具有最大關鍵字的元素
extractmax(a):去掉並返回a中最大關鍵字的元素
increasekey(a,x,k):將元素x的關鍵字值增加到k,假設k的值不小於x的原關鍵字值
最大優先佇列:記錄將要執行的各個作業以及它們之間的相對優先順序。當乙個作業完成或者被中斷,排程器將呼叫extractmax(a)從所有的等待作業中,選出具有最高優先順序的作業來執行。在任何時候,排程器可以呼叫insert(a,x)把乙個新作業加入到佇列中來
最小優先佇列:可以用於基於事件驅動的模擬器,佇列中儲存要模擬的事件,每個事件都有乙個發生時間作為其關鍵字。事件必須按照發生的時間順序進行模擬,因為某一事件的模擬結果可能會觸發對其他事件的模擬。在每一步,模擬程式呼叫extractmin(a)來選擇下乙個要模擬的事件。當乙個新事件產生時,模擬器通過呼叫insert將其插入最小優先順序對列中
優先佇列可以用堆來實現。我們需要確定那個物件對應乙個給定的優先佇列元素。再用堆來實現優先佇列時,需要在堆的每個元素裡儲存對應物件的控制代碼。控制代碼(如乙個指標或乙個整型數):的準確含義依賴於具體的應用程式。同樣,在應用程式的物件中,也需要儲存乙個堆中對應元素的控制代碼。通常,這個控制代碼是陣列的下標。由於在堆的操作過程中,元素會改變其在陣列中的位置,因此,在具體的實現中,在重新確定堆元素位置時,我們也需要更新相應應用程式物件中的陣列下標
相應**
int
heapmaximum
(int a,
int heapsize)
intheapextractmax
(int a,
int*heapsize)
int temp = a[1]
; a[1]
= a[
*heapsize]
; a[
*heapsize]
= temp;
*heapsize -=1
;maxheapify
(a,*heapsize,1)
;return temp;
}void
heapincreasekey
(int a,
int i,
int key)
a[i]
= key;
int temp;
while
(i>
1&& a[
parent
(i)]
< a[i])}
void
heapinsert
(int a,
int* heapsize,
int key)
堆 優先佇列 堆排序
堆就是在二叉樹上滿足每乙個根節點都大於兩個子節點的資料結構。堆常用來解決兩個問題,堆排序和優先佇列。堆的核心在於如何維護,通過比較來進行遞迴維護。相比於佇列加二分插入的實現,堆可以基於已經有的結果在最長lgn的時間內實現,通常比較到無需換位即可,而二分插入往往都要lgn,define maxn 10...
排序演算法 四 優先佇列 二叉堆以及堆排序
我們經常會碰到下面這種情況,並不需要將所有資料排序,只需要取出資料中最大 或最小 的幾個元素,如排行榜。那麼這種情況下就可以使用優先佇列,優先佇列是乙個抽象資料型別,最重要的操作就是刪除最大元素和插入元素,插入元素的時候就順便將該元素排序 其實是堆有序,後面介紹 了。二叉堆其實是優先佇列的一種實現,...
python實現堆的建立和優先佇列
關於二叉樹 二叉樹的特點 二叉樹是一種儲存資料元素的匯集資料結構。二叉樹最重要的性質就是樹的高度和樹中可以容納的最大結點個數之間的關係。樹的高度類似於表長,是從根結點到其他結點的最大距離。在長為n的表裡只能容納n個結點,而在高為h的二叉樹中則可以容納大約2 h個結點,這是表和樹的最大不同點。一般的元...