第五部分 高級數據結構
第19章 斐波那契堆
兩種用途:
1. 支持一系列操作,這些操作構成了所謂的“可合併堆”;
2. 這些操作可以在常數攤還時間內完成,使得非常適合於需要頻繁調用這些操作的應用;
1. 斐波那契堆結構
一個斐波那契堆是一系統具有最小堆序的有根樹的集合。也就是說,每棵樹均遵循最小堆性質:每個結點的關鍵字大於或等於它的父結點的關鍵字。
每個結點x包含一個指向它父結點的指針x.p和一個指向它的某一個孩子的指針x.child。x的所有孩子被鏈接成一個環形的雙向鏈表,稱爲x的孩子鏈表。孩子鏈表中的每個孩子y均有指針y.left和y.right,分別指向y的左兄弟和右兄弟。如果y是僅有的一個孩子,則y.left = y.right =y。
結點x的孩子鏈表中的孩子數目儲存在x.degree。布爾值屬性x.mark指示結點x自從上一次成爲另一個結點的孩子後,是否失去過孩子。
通過指針H.min來訪問一個給定的斐波那契堆H,該指針指向具有最小關鍵字的樹的根結點,我們把這個結點稱爲斐波那契堆的最小結點。
如果一個斐波那契堆H是空的,那個H.min爲NIL。
H.n表示H中當前的結點數目。
勢函數
t(H)表示H中根鏈表中樹的數目,m(H)表示H中已標記的結點數目。H的勢函數如想:
Φ(H) = t(H) + 2m(H)
2. 可合併堆操作
創建一個新的斐波那契堆
創建一個空的H,Make-Fib-Heap分配並返回一個Fib對象H,其中H.n = 0和H.min = NIL,H中不存在樹。
因爲 t(H) =0和m(H) =0,Φ(H) = 0。因此,Make-Fib-Heap的攤還代價等於它的實際代價O(1)
插入一個結點
Fib-Heap-Insert(H, x)
x.degree = 0
x.p = NIL
x.child = NIL
x.mark = FALSE
if H.min == NIL
create a root list for H containing just x
H.min = x
else
insert x into H's root list
if x.key < H.min.key
H.min = x
H.n = H.n + 1
t(H’) = t(H’) + 1
m(H’) = m(H)
勢的增加量爲: ( t(H) + 1 + 2m(H)) - ( t(H) + 2m(H)) = 1
實際代價爲O(1),因此攤還代價爲O(1) + 1 = O(1)
尋找最小結點
最小結點可通過H.min得到。因此,可以在O(1)的實際代價內找到最小結點。H的勢沒有發生變化,因此該操作的攤還代價等於它的初階代價O(1)。
兩個斐波那契堆的合併
將H1和H2的根鏈表鏈接,然後確定新的最小結點。之後,銷燬H1和H2,表示H1和H2的對象將不再使用。
Fib-Heap-Union(H1, H2)
H = Make-Fib-Heap()
H.min = H1.min
concatenate the root list of H2 with the root list of H
if (H1.min == NIL) or (H2.min != NIL and H2.min.key < H1.min.key)
H.min = H2.min
H.n = H1.n + H2.n
return H
勢函數變化爲:
Φ(H) - (Φ(H1)+Φ(H2)) = (t(H)+2m(H)) - ((t(H1)+2m(H1)) + (t(H2)+2m(H2))) = 0
攤還代價等於它的實際代價O(1)
抽取最小結點
Fib-Heap-Extract-Min(H)
z = H.min
if z != NIL
for each child x of z
add x to the root list of H
x.p = NIL
remove z from the root list of H
if z == z.right
H.min = NIL
else
H.min = z.right
Consolidate(H)
H.n = H.n - 1
return z
Consolidate(H)
let A[0..D(H.n)] be a new array
for i = 0 to D(H.n)
A[i] = NIL
for each node w in the root list of H
x = w
d = x.degree
while A[d] != NIL
y = A[d] // another node with the same degree as x
if x.key > y.key
exchange x with y
Fib-Heap-Link(H, y, x)
A[d] = NIL
d = d + 1
A[d] = x
H.min = NIL
for i = 0 to D(H.n)
if A[i] != NIL
if H.min == NIL
create a root list for H containing just A[i]
H.min = A[i]
else
insert A[i] into H's root list
if A[i].key < H.min.key
H.min = A[i]
Fib-Heap-Link(H, y, x)
remove y from the root list of H
make y a child of x, incrementing x.degree
y.mark = FALSE
攤還時間爲O(lgn)
3.關鍵字減值和刪除一個結點
Fib-Heap-Decrease-Key(H, x, k)
if k > x.key
error "new key is greater than current key"
x.key = k
y = x.p
if y != NIL and x.key < y.key
Cut(H, x, y)
Cascading-Cut(H, y)
if x.key < H.min.key
H.min = x
Cut(H, x, y)
remove x from the child list of y, decrementing y.degree
add x to the root list of H
x.p = NIL
x.mark = FALSE
Cascading-Cut(H, y)
z = y.p
if z != NIL
if y.mark = FALSE
y.makr = TRUE
else
Cut(H, y, z)
Cascading-Cut(H, z)
攤還時間爲O(1)
4. 刪除一個結點
Fib-Heap-Delete(H, x)
Fib-Heap-Decrease-Key(H, x, -∞)
Fib-Heap-Extract-Min(H)
攤還時間爲O(lgn)