1.模型
兩個基本操作:
insert等價enqueue
deletemin刪除最小者–dequeue
2.簡單的實現
(1)簡單鍊錶–遍歷刪除min或者排序刪除min
(2)使用二叉查詢樹。
反覆除去min會使得樹不平衡,並且bst還支援許多不需要的操作。
3.二叉堆
優先佇列的實現普遍使用二叉堆,堆有兩個性質–結構性和堆序性,對堆的一次操作可能破壞兩個性質中的乙個,因此堆的操作必須要到堆的性質都被滿足時才能終止。
(1)結構性質:堆是一棵除了底層,完全填滿的二叉樹,底層的元素從左到右填入。–完全二叉樹
儲存:陣列儲存,對位置i,其左兒子在2*i上,右兒子在2*i+1 上,父親則在位置floor(i/2)上。
資料結構:陣列,代表最大容量的整數以及當前堆大小組成。
(2)堆序性質:在乙個堆中,對於每乙個節點x,x的父親中的關鍵字小於等於x中的關鍵字,根節點是最小元素.–最小堆
反之,大於等於–最大堆
因此優先佇列可以用來找出和刪除最小元或者最大元,這需要提前決定。本節討論最小堆。
(3)基本操作:
插入–上濾
位置0放置乙個很小的值,稱為標記,使用這種啞資訊避免了每個迴圈都要執行一次的測試,從而節省了一些時間。
刪除最小元–下濾
將x置入沿著從根開始包含最小兒子的一條路徑上的乙個正確位置。
(4)其他操作:
問題:按照最小堆設計的資料結構在求最大元方面卻無任何幫助,實際上對任何特定的關鍵字查詢都是沒有幫助的(除了線性查詢).
如果我們知道每個元素的具體位置,那麼下面幾個操作的開銷將會變小–
操作:
降低關鍵字的值decreasekey(p,x,h)–上濾
增加關鍵字的值increasekey(p,x,h)–下濾
刪除delete(p,h)–執行decreasekey(p,無窮,h)–執行–deletemin(h)
構建堆buildheap(h)–n個相繼的insert操作
或者直接讀入乙個陣列,執行上濾操作
定理
包含2^(b+1) - 1 個節點高為b的理想二叉樹的節點的高度和為2^(b+1)-1-(b+1)
證明–乘公比錯位相減法。
4.優先佇列的應用
(1)選擇問題
未排序的陣列中大小為第k個的元素的值
演算法a:將n個元素讀入乙個陣列,然後對陣列應用buildheap演算法,執行k次deletemin操作,從該堆最後提取的元素就是答案。
如果k=n執行此演算法並在元素離開堆的時候記錄它們的值,那麼我們實際上已經對輸入檔案以時間o(n logn)作了排序–堆排序
演算法b:前k個元素通過呼叫一次buildheap以o(k)被置入堆中,其餘的元素中如果有比堆中max小的就deletemax(h),然後insert之.中位數的時間界是nlogn.最後返回findmax.–最大堆
(2)事件模擬–銀行排隊問題等等
5.d-堆
(1) 二叉堆的推廣,只是所有的節點都有d個兒子。
(2) 當優先佇列太大不能完全裝入主存的時候,d-堆能夠以b-樹大致相同的方式發揮作用,並且實踐中4-堆可以勝過二叉堆。
(3)堆的缺點:
a.不能執行find
b.將兩個堆合併成乙個堆是困難的操作–合併merge,但是許多實現堆的方法使得merge操作的執行時間是o(log n)
6.左式堆
任一 節點x的零路徑長npl(x)定義為從x到乙個沒有兩個兒子的節點的最短路徑的長。因此具有乙個或者零個兒子的節點的npl為0,而npl(null)=-1.
(1)左式堆和二叉樹唯一的區別是:左式堆不是理想平衡的,而實際上是趨於非常不平衡.
(2)性質:
a.任一節點的零路徑長都比它的諸兒子節點的零路徑長的最小值多1。
b.對於堆中的每乙個節點x,左兒子的零路徑長至少和右兒子的零路徑長一樣大,故不平衡,更偏重於使樹向左增加深度,但便於合併操作。沿左式堆的右路徑確實是堆中最短的路徑.
(3)定理:
在右路徑上有r個節點的左式堆必然至少有2^r -1個節點。
n個節點的左式堆有一條右路徑最多含有floor(log(n+1))個節點,對左式堆操作的思路一般是將所有的工作放到右路徑上進行,它保證樹身短。
7.斜堆
(1)左式堆的自調節形式,斜堆是具有堆序的二叉樹,但是不存在對樹的結構限制。不同於左式堆,關於任意節點的零路徑長的任何資訊都不保留,斜堆的右路徑在任意時刻都可以任意長,因此所有操作的最壞情形的執行時間均為o(n),但可以證明任意m次連續操作,總的最壞情形執行時間是o(mlogn),因此斜堆每次操作的攤還時間為o(logn).這點與伸展樹類似.
(2)合併操作:對於左式堆,我們檢視是否左兒子和右兒子滿足左式堆堆序的性質,並交換那些不滿足該性質者,但對於斜堆,除了這些右路徑上所有節點的最大者不交換它們的左右兒子,交換是無條件的.
(3)優點:不需要附加的空間來保留路徑長度以及不需要測試確定何時交換兒子.
8.二項佇列
(1)二項佇列不是一棵堆序的樹,而是堆序的樹的集合,稱為森林,堆序樹中的每一棵都是有約束的形式,叫做二項樹。每乙個高度上至多存在一棵二項樹,高度為0的二項樹是一棵單節點樹,高度為k的二項樹bk通過將一棵二項樹bk-1附接到另一棵二項樹bk-1的根上而構成.
二項樹bk由乙個帶有兒子b0,b1,……bk-1的根組成,高度為k的二項樹恰有2^k個節點,而在深度d處的節點數是二項係數(k,d),如果我們把堆序施加到二項樹上並允許任意高度上最多有一棵二項樹,那麼我們能夠用二項樹的集合唯一的表示任意大小的優先佇列.
(2)操作
a.finmin:最小元可以通過搜尋所有的樹的根來找出,由於最多有logn棵不同的樹,因此最小元可以時間o(logn)找到.
b.合併操作:通過將兩個佇列加到一起來完成–類似二進位制的加法運算一樣.
加一次花費常數時間,總共logn棵二項樹,因此合併在最壞情形下花費時間o(logn).如果將這些樹放到按照高度排序的二項佇列中,該操作會更加高效.
c.插入–建立乙個單節點樹並執行一次合併
先執行:
然後合併:
(3)儲存
二項樹的每乙個節點將包含資料,第乙個兒子以及右兄弟.且二項樹中的諸兒子以遞減次序排列.
注意:
樹的秩:樹節點容量的度量,b+樹中每個節點包含目錄項的個數m需滿足d≤m≤2d,根節點是1≤m≤2d。其中d為樹的秩
總結
優先佇列
(1)二叉堆
(2)左式堆–遞迴
(3)斜堆–缺少平衡原則
(4)二項佇列
應用:作業系統的工作排程到模擬
優先佇列 堆
印表機列印作業一般是放在佇列中的。如果按照先來先列印的順序,有乙個100頁的列印任務,那麼會讓後面短小的任務等待很長時間。更合理的做法也許是最後處理最耗時的列印任務,不管它是不是最後提交上來的。在多使用者作業系統中,作業系統讓哪個程式使用cpu,是需要決定從佇列裡面選擇的。一般做法是從隊頭獲得程式,...
優先佇列 堆
優先佇列 佇列是乙個操作受限的線性表,資料只能在一端進入,另一端出來,具有先進先出的性質。有時在佇列中需要處理優先順序的情況,即後面進入的資料需要提前出來,這裡就需要優先佇列。優先佇列是至少能夠提供插入和刪除最小值這兩種操作的資料結構。對應於佇列的操作,插入相當於入隊,刪除最小相當於出隊。鍊錶,二叉...
堆 優先佇列
面試的時候被問到了heapsort,發現自己對資料結構這塊的理解實在不夠,最近打算推翻重新來學一遍。這裡先簡單地說一下自己對堆的理解。堆的特質 1.平衡二叉樹 保證了操作時間複雜度為logn 2.以最小堆為例,對任意結點,其父節點均小於子節點。這樣幾乎各種操作都是在縱向上 深度 進行的。由於在堆這個...