跟我一起学算法——斐波那契堆

斐波那契堆(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. 预定义

  1. 势函数定义
    f(H)=t(H)+2m(H)
    f表示势函数,t表示树的个数,m表示mark=true的结点数。
  2. 平摊分析
    C^i = C_i + f(i) - f(i-1)
    C^i:平摊成本
    C_i:操作的实际成本
    f(i-1):操作前的势能
    f(i):操作后的势能
  3. 任意结点的最大度上界 D(n)
  4. 无序二项树U_k
    不要求按子树的度的大小排列。

4. 五个基本操作

  1. 创建空堆
  2. 插入结点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)
  3. 查找最小值结点
    head
    平摊成本O(1)
  4. 合并堆
    step1:合并根表
    step2:检查head
    平摊成本O(1)
  5. 抽取最小值结点z
    平摊成本O(D(n))
  • 将z的子树插入根表
  • delete z, head随意指
  • 清理根表,防止根表过大。合并相同度的树,重构堆,并将head指向最小结点。
    使用一个辅助指针数组A[0,..., D(n[H])],高效合并和重构堆。D(n[H])表示根结点的最大度。
    数组下标表示度,数组元素为根节点指针,初始化为null。合并度相同的树,最终使根表中的度是
    唯一的。
    注意:以head为起点,向右扫描根表,同时合并相同度的二项树,直到根表中的树具有唯一的度。

5.两个扩展操作

  1. 结点减值
  • 根结点减值后不需要后续操作
  • 非根结点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)
  1. 删除结点
  • x结点减值到MIN
  • 抽取最小值

参考

《算法导论》

posted @ 2020-03-03 15:20  chzhyang  阅读(374)  评论(0编辑  收藏  举报