從以上定義,不難得到下面的結論:
二項堆由一組二項樹所構成,這裡的二項樹需要滿足下列條件:
1)h中的每個二項樹遵循最小堆的性質。
2)對於任意非負整數k,在h中至多有一棵二項樹的根具有度數k。
對於性質2,任意高度最多有一棵二項樹,這樣就可以用二項樹的集合唯一地表示任意大小的二項堆,比如13個結點的二項堆h,13的二進位制表示為(1101),故h包含了最小堆有序二項樹b3, b2和b0, 他們分別有8, 4, 2, 1個結點,即共有13個結點。如下圖(另外:二項堆中各二項樹的根被組織成乙個鍊錶,稱之為根表)
}由於每乙個二項樹都滿足最小堆的性質,所以每個二項樹的最小關鍵字一定在根結點,故只需遍歷比較根表的情況就可以。
binheap findbinheapmin(binheap heap)
}return min_node;
}
合併兩個二項堆有三個函式:
binomial-pair,連線操作,即將兩棵根節點度數相同的二項樹bk-1連線成一棵bk。
binomial-heap-merge ,將h1和h2的根表合併成乙個按度數的單調遞增次序排列的鍊錶。
binomial-heap-union,反覆連線根節點的度數相同的各二項樹。
合併操作分為兩個階段:
第一階段:執行binomial-heap-merge,將兩個堆h1和h2的根表合併成乙個鍊錶h,它按度數排序成單調遞增次序。merge的時間複雜度o(logn)。n為h1和h2的結點總數。(對於每乙個度數值,可能有兩個根與其對應,所以第二階段要把這些相同的根連起來)。
第二階段:將相等度數的根連線起來,直到每個度數至多有乙個根時為止。執行過程中,合併的堆h的根表中至多出現三個根具有相同的度數。(merge後h中至多出現兩個根具有相同的度數,但是將兩個相同度數的根的二項樹連線後,可能與後面的至多兩棵二項樹出現相同的度數的根,因此至多出現三個根具有相同的度數)
第二階段根據當前遍歷到的根表中的結點x,分四種情況考慮:
case1:degree[x] != degree[sibling[x]]。此時,不需要做任何變化,將指標向根表後移動即可。(下圖示a)
case2:degree[x] == degree[sibling[x]] == degree[sibling[sibling[x]]]。此時,仍不做變化,將指標後移。(下圖示b)
case3 & case4:degree[x] = degree[sibling[x]] != degree[sibling[sibling[x]]] (下圖示c和d)
case3:key[x] <= key[sibling[x]]。此時,將sibling[x]連線到x上。
case4:key[x] > key[sibling[x]]。此時,將x連線到sibling[x]上。
複雜度:o(logn), 四個過程變化情況:
//********************===兩個二項佇列的連線*************************===
binheap binheapunion(binheap h1, binheap h2)
//case 3、4:相鄰2個相等,和第3個不等
else
//case 4: 將x連到x_next
else
}//case 3&4
x_next = x->sibling;
}//while
return heap;
}//將2個二項佇列合併成度數單調遞增的乙個二項佇列
binheap binheapmerge(binheap h1, binheap h2)
else
if(h3_prev ==
null)
else
}//while
if(h1 ==
null)
h3_prev->sibling = h2;
else
if(h2 ==
null)
h3_prev->sibling = h1;
}if(h1 ==
null)
if(h2 ==
null)
return heap;
}//連線2個度數k相同的二項樹成度數為k+1的一棵樹,將h1 連線到 h2上
先建立只有該結點的二項堆,然後在與原來的二項堆合併。
//用陣列元素建立二項佇列
binheap creatheapwitharray(item a, int n)
memset(newheap, 0, sizeof(*newheap));
newheap->key = a[i];
if(heap == null)
heap = newheap;
else
}return heap;
}
從根表中找到最小關鍵字的結點,將以該結點為根的整棵二項樹從堆取出,刪除取出的二項樹的根,將其剩下的子女倒序排列,組成了乙個新的二項堆,再與之前的二項堆合併。
binheap binheapdelmin(binheap h1)
p = p->sibling;
}binheap heap = h1;
if(h1 ==
min)
heap =
min->sibling;
else
min_prev->sibling =
min->sibling;
binheap x_prev =
null, x =
null; //
binheap h2 =
null;
p =null;
x =min->leftchild;
while (x !=
null)
heap = binheapunion(heap, h2);
return
min;
}
優先佇列 堆 二項佇列
目錄四 二項佇列的實現 位址 我們知道,左式堆每次操作的時間界是 o logn 二項佇列支援合併 插入 刪除最小值,每次插入的平均時間為常數時間,而最壞時間是 o logn 二項佇列 結構 高度為0的二項樹是一棵單節點樹,例如b0。高度為k的二項樹 b k 通過將一棵二項樹 b 附接到另一棵二項樹 ...
優先佇列《堆》
1.模型 兩個基本操作 insert等價enqueue deletemin刪除最小者 dequeue 2.簡單的實現 1 簡單鍊錶 遍歷刪除min或者排序刪除min 2 使用二叉查詢樹。反覆除去min會使得樹不平衡,並且bst還支援許多不需要的操作。3.二叉堆 優先佇列的實現普遍使用二叉堆,堆有兩個...
優先佇列 堆
印表機列印作業一般是放在佇列中的。如果按照先來先列印的順序,有乙個100頁的列印任務,那麼會讓後面短小的任務等待很長時間。更合理的做法也許是最後處理最耗時的列印任務,不管它是不是最後提交上來的。在多使用者作業系統中,作業系統讓哪個程式使用cpu,是需要決定從佇列裡面選擇的。一般做法是從隊頭獲得程式,...