1. 程式人生 > >優先隊列的實現

優先隊列的實現

info 通過 one delet pan 實現 堆排序 完全二叉樹 存在

實現優先隊列結構主要是通過堆完成,主要有:二叉堆、d堆、左式堆、斜堆、二項堆、斐波那契堆、pairing 堆等。

1. 二叉堆

1.1. 定義

完全二叉樹,根最小。

存儲時使用層序。

技術分享圖片

1.2. 操作

(1). insert(上濾)

插入末尾 26,不斷向上比較,大於26則交換位置,小於則停止。

技術分享圖片

(2). deleteMin(下濾)

提取末尾元素,放在堆頂,不斷下濾:

技術分享圖片

(3). 其他操作:

都是基於insert(上濾)與deleteMin(下濾)的操作。

減小元素:減小節點的值,上濾調整堆。

增大元素:增加節點的值,下濾調整堆。

刪除非頂點節點:直接刪除會出問題。方法:減小元素的值到無窮小,上濾後刪除。

Merge:insert one by one

2. d叉堆

2.1. 定義

完全d叉樹,根最小。

存儲時使用層序。

技術分享圖片

2.2. 操作:

操作跟二叉堆基本一致:insert,deleteMin,增大元素,減小元素,刪除非頂元素,merge。

技術分享圖片

2.3 二叉堆與d叉堆的對比:

技術分享圖片

3. 左式堆

3.1. 定義

零路徑長度:到沒有兩個兒子的節點最短距離 左式堆: 1.一棵二叉樹 2.零路徑長:左兒子≧右兒子,父節點= min{兒子} +1(這條性質導致了左式堆的嚴重左偏) 零路徑長度: 技術分享圖片

3.2. 操作:

(1) merge :

原則:根值大的堆與根值小的堆的右子堆合並(根值:根位置的元素值,並非零路徑長度) 技術分享圖片
具體分三種情況(設堆H1的根值小於H2) H1只有一個節點 H1根無右孩子 H1根有右孩子 (1.1).H1只有一個節點,若出現不滿足:零路徑長:左兒子≧右兒子,交換左右孩子。 技術分享圖片 (1.2).H1根無右孩子,若出現不滿足:零路徑長:左兒子≧右兒子,交換左右孩子。

技術分享圖片

(1.3).H1根有右孩子

1.初始狀態,H1的根6,H2的根為8,將H2合並到H1。

技術分享圖片

2.將H1構造成根無右孩子的形式:

技術分享圖片

3.將元素10, merge到H2,要首先將H2構造成根無右孩子的形式,遞歸,merge,若出現不滿足:零路徑長:左兒子≧右兒子,交換左右孩子……

技術分享圖片——》技術分享圖片——》技術分享圖片——》技術分享圖片

4.

技術分享圖片

5.

技術分享圖片

3.3. 性質分析:

insert:merge deleteMin:delete root,merge 時間復雜度:merge與右路徑長度之和成正比;最壞O(logN) 缺點:交換需判斷;維護零路徑長

4. 斜堆

4.1. 定義

二叉樹,根最小。由此可見: 技術分享圖片 特點:merge無條件交換。 時間復雜度:最壞O(N);最好?(1);平均O(logN)

4.2性能比較:

技術分享圖片

定義

  • 僅有一個節點的樹為斜堆;
  • 兩個斜堆合併的結果仍為斜堆。

合併操作

斜堆合併操作的遞歸合併過程和左偏樹完全一樣。假設我們要合併 A 和 B兩個斜堆,且 A 的根節點比 B 的根節點小,我們只需要把 A 的根節點作為合併後新斜堆的根節點,並將 A 的右子樹與 B 合併。由於合併都是沿著最右路徑進行的,經過合併之後,新斜堆的最右路徑長度必然增加,這會影響下一次合併的效率。所以合併後,通過交換左右子樹,使整棵樹的最右路徑長度非常小(這是啟發規則)。然而斜堆不記錄節點的距離,在操作時,從下往上,沿著合併的路徑,在每個節點處都交換左右子樹。通過不斷交換左右子樹,斜堆把最右路徑甩向左邊了。

遞歸實現合併

  • 比較兩個堆; 設p是具有更小的root的鍵值的堆,q是另一個堆,r是合併後的結果堆。
  • 令r的root是p(具有最小root鍵值),r的右子樹為p的左子樹。
  • 令r的左子樹為p的右子樹與q合併的結果。

舉例。合併前: 技術分享圖片


合併後 技術分享圖片

非遞歸合併實現

  • 把每個堆的每棵(遞歸意義下)最右子樹切下來。這使得得到的每棵樹的右子樹均為空。
  • 按root的鍵值的升序排列這些樹。
  • 叠代合併具有最大root鍵值的兩棵樹:
    • 具有次大root鍵值的樹的右子樹必定為空。把其左子樹與右子樹交換。現在該樹的左子樹為空。
    • 具有最大root鍵值的樹作為具有次大root鍵值樹的左子樹。

舉例: 技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

5. 總結

技術分享圖片

如果是不支持所謂的合並操作union的話,普通的堆數據結構就是一種很理想的數據結構(堆排序)。 但是如果想要支持集合上的合並操作的話,最好是使用二項堆或者是斐波那契堆,普通的堆在union操作上最差的情況是O(n),但是二項堆和斐波那契堆是O(lgn)。

技術分享圖片

優先隊列的實現