跟我一起学算法——斐波那契堆
斐波那契堆(Fibonacci Heap)
1. 定义
FibHeap是一个树的集合,且树满足最小堆性质。根表不要求树根的度有序,head指向根表中值最小
的结点。全部使用双向循环链表。
KEY:防止超出O(lgn)的操作出现,也即防止出现度超过O(lgn)的树出现,只要能保证D(n)<=
lgn,其性能优于二项堆。
2. 数据结构
- 结点的域
p:父指针
left,right:左右指针
key:值
degree:度
child:指向任意孩子
mark:非常重要的标志位。创建结点或结点成为孩子时,mark=false,结点失去一个孩子时,mark=true。 - 根表以及结点间 双向循环链表
3. 预定义
- 势函数定义
f(H)=t(H)+2m(H)
f表示势函数,t表示树的个数,m表示mark=true的结点数。 - 平摊分析
C^i = C_i + f(i) - f(i-1)
C^i:平摊成本
C_i:操作的实际成本
f(i-1):操作前的势能
f(i):操作后的势能 - 任意结点的最大度上界 D(n)
- 无序二项树U_k
不要求按子树的度的大小排列。
4. 五个基本操作
- 创建空堆
- 插入结点x
将x作为U_0树插入根表,检查head, x.mark=false。
平摊分析:
C_i = O(1)
f(i)-f(i-1)=t(H')-t(H)+2m(H') -2m(H)=1+0=1
则C^i=O(1) - 查找最小值结点
head
平摊成本O(1) - 合并堆
step1:合并根表
step2:检查head
平摊成本O(1) - 抽取最小值结点z
平摊成本O(D(n))
- 将z的子树插入根表
- delete z, head随意指
- 清理根表,防止根表过大。合并相同度的树,重构堆,并将head指向最小结点。
使用一个辅助指针数组A[0,..., D(n[H])],高效合并和重构堆。D(n[H])表示根结点的最大度。
数组下标表示度,数组元素为根节点指针,初始化为null。合并度相同的树,最终使根表中的度是
唯一的。
注意:以head为起点,向右扫描根表,同时合并相同度的二项树,直到根表中的树具有唯一的度。
5.两个扩展操作
- 结点减值
- 根结点减值后不需要后续操作
- 非根结点x减值后如果破坏了最小堆性质,则需要后续操作
- 切断x与其父结点y的关系,把x加入根表,x.mark=Flase
- 级联切断 递归检查y结点,如果x是它被剪掉的第二个孩子(y.mark=TRUE),则y也从原
树中脱离,加入根表,同时y=y.p,继续检查,直到y.mark=false或y=root - 别忘记重新确定head->min
fibHeap_decrease(h, x, k):
if k > x.KEY:
error
return
x.key = k
y = x.p
if y is not None and x.key < y.key:
# 切 x
cut(h, x, y)
# 级联切断
cascading_cut(H, y)
# 检查head
if x.key < h.min.key :
h.min = x
cut(h,x,y):
remove x from y
y.degree -= 1
add x to rootlist
x.p = None
# 关键
x.mark = FALSE
cascading_cut(H, y):
z = y.p
if z is not None:
if y,mark == FALSE:
y.mark = TRUE
else :
cut(H,y,z)
cascading_cut(H,z)
- 删除结点
- x结点减值到MIN
- 抽取最小值
参考
《算法导论》