作者: 大树先生
博客: http://blog.csdn.net/koala_tree
GitHub:https://github.com/koalatree
2017 年 09 月 13 日
自《算法导论》.
斐波那契堆有两种用途:第一种,支持一系列操作,这些操作构成了所谓的“可合并堆”。第二种,斐波那契堆的一些操作可以在常数摊还时间内完成。
可合并堆的两种实现方式下各操作的运行时间。在操作时堆中的项数用n表示。
一个斐波那契堆是一系列具有最小堆序的有根树的集合。也就是说,每棵树均遵循最小堆性质:每个结点的关键字大于或等于它的父结点的关键字。
结点属性:
势函数:
使用势方法来分析斐波那契堆操作的性能。
最大度数:
在一个n个结点的斐波那契堆中任何结点的最大度数都有上界 D(n)⩽⌊lgn⌋ .
过程分配并返回一个斐波那契堆对象H,其中H.n=0和H.min = NIL,H中不存在树。
由于 t(H)=0,m(H)=0 ,空斐波那契堆的势为 Φ(H)=0 ,因此创建新堆的摊还代价等于他的实际代价 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) ,则增加的势能为1,实际代价为 O(1) ,摊还代价为 O(1)+1=O(1) .
通过指针H.min得到。可以在 O(1) 的实际代价内找到最小结点。
合并斐波那契堆 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
势函数变化为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
以上代码用到的合并(Consolidating)H根链表的操作,通过调用Consolidating(H)来减少斐波那契堆中树的数目。
过程重复执行以下步骤:
使用辅助数组 A[0..D(H.n)] 记录根结点对应的度数的轨迹。如A[i] = y,那么当前的y是一个具有y.degree = i的根。
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(D(n))=O(lgn) .
摊还时间: O(1) .
Fib_heap_decrease_key(H, x, k)
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 = z.p
if z /= NIL
if y.mark == FALSE
y.mark = TRUE
else Cut(H, y, z)
Cascading_cut(H, z)
斐波那契堆中规定,某个结点x一旦失掉第二个孩子,就切断x与其父结点的链接,是它称为一个新的跟。
所以,如果切掉的结点是其父结点的第二个孩子,则需要进行一次级联切断(cascading cut)。
过程示意图:
摊还时间: O(D(n))=O(lgn) .
Fib_heap_delete(H, x)
Fib_heap_decrease_key(H, x, -inf)
Fib_heap_extract_min(H)
O(1)+O(D(n))=O(D(n))=O(lgn) .