算法导论读书笔记-第十九章-斐波那契堆

算法导论第19章--斐波那契堆

可合并(最小)堆(mergeable min-heap) : 支持以下5种操作的一种数据结构, 其中每一个元素都有一个关键字:

  • MAKE-HEAP(): 创建和返回一个新的不含任何元素的堆.
  • INSERT(H, x): 将一个已填入关键字的元素x插入堆H中.
  • MINIMUM(H): 返回一个指向堆H中具有最小关键字元素的指针.
  • EXTRACT-MIN(H): 从堆H中删除最小关键字的元素, 并返回一个指向该元素的指针.
  • UNION(H1, H2): 创建并返回一个包含堆H1和堆H2中所有元素的新堆, 原来的H1和H2被销毁.

斐波那契堆 : 除可合并堆支持的操作外, 还支持以下两种操作:

  • DECREASE-KEY(H, x, k): 将堆H中元素x的关键字赋予新值k, 且k不大于当前的关键字.
  • DELETE(H, x): 从堆H中删除元素x.

19.1 斐波那契堆结构

斐波那契堆 : 一系列具有最小堆序的有根树的集合, 即每棵树均遵循最小堆性质.

斐波那契堆的结构:

  • 每个结点x包含一个指向父结点的指针x.p, 一个指向它的某一个孩子的指针x.child.
  • x的所有孩子被链接成一个环形的双向链表, 称为x的孩子链表. 孩子链表中的每个孩子y均有指针y.left和y.right, 分别指向y的左兄弟和右兄弟. 如果y是仅有的一个孩子, 则y.left = y.right = y. 孩子链表中各兄弟出现的次序任意.
  • 每个结点有另外两个属性: x.degree表示x的孩子链表中的孩子数目. x.mark表示x自从上一次成为另一个结点的孩子后, 是否失去过孩子.新产生的结点是未被标记的, 并且当结点x成为另一个孩子时, 更新为未被标记结点.
  • 指针H.min指向堆H中具有最小关键字的树的根结点. 若不止一个根结点具有最小关键字, 则这些根结点中的任何一个都有可能成为最小结点. 若H为空, 则H.min为NIL.
  • 所有树的根也用left和right指针连接成一个环形的双链表, 称为斐波那契堆的根链表. 根链表中的树次序可以任意.
  • H.n表示H中当前的结点数目.

19.2 可合并堆操作

斐波那契堆上的一些可合并堆操作要尽可能长地延后执行, 不同的操作可以进行性能平衡.

创建一个新的斐波那契堆

def make_fib_heap():
  分配并返回一个斐波那契堆对象H
  H.n = 0
  H.min = NIL

实际代价O(1), 摊还代价O(1).

插入一个结点

# 将结点x插入斐波那契堆H中
# 假定该结点已经被分配, x.key已经赋值
def fib_heap_insert(H, x):
  x.degree = 0
  x.p = None
  x.child = None
  x.mark = False
  if H.min is None:
    # 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

实际代价O(1), 摊还代价O(1).

寻找最小结点

直接通过H.min得到, 实际代价O(1), 摊还代价O(1).

两个斐波那契堆的合并

# 合并斐波那契堆H1和H2, 并在该过程中销毁H1和H2
def 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 is None) or (H2.min is not None and H2.min.key < H1.min.key):
    H.min = H2.min
  H.n = H1.n + H2.n
  return H

实际代价O(1), 摊还代价O(1).

抽取最小结点

def fib_heap_extract_min(H):
  z = H.min
  if z is not None:
    for x in z.childlist:
      # add x to the root list of H
      x.p = None
    # remove z from the root list of H
    # assume the fields of z remain
    if z == z.right:
      H.min = None
    else:
      H.min = z.right
      consolidate(H)
    H.n = H.n - 1
  return z

没有辅助过程consolidate也能满足斐波那契堆的性质, 但是根链表会越来越长, 使得整个堆几乎就是一个链表, 那些尽可能延后的工作的性能就不能平衡了, 因此需要通过consolidate过程来合并H的根链表, 减少链表上根的数目.

# 合并H的根链表, 减少斐波那契堆中树的数目.
# 重复以下步骤直到根链表中的每一个根有不同的度数
# 1.在根链表中找到两个具有相同度数的根x和y, 假定x.key<=y.key
# 2.把y链接到x.
def consolidate(H):
  let A[0...D(H.n)] be a new array
  # D(H.n)是最大度数的上界
  for i in range(D(H.n)+1):
    A[i] = None
  for w in H.rootlist:
    x = w
    d = x.degree
    while A[d] is not None:
      y = A[d]
      if x.key > y.key:
        swap(x,y)
      fib_heap_link(H,y,x)
      A[d] = None
      d = d + 1
    A[d] = x
  H.min = None
  for i in range(D(H,n)+1):
    if A[i] is not None:
      if H.min is None:
        # 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]
def 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

fib_heap_extract_min摊还代价为O(D(n)), 而D(n) = O(lgn), 因此摊还代价为O(lgn).

19.3 关键字减值和删除一个结点

关键字减值

def fib_heap_decrease_key(H, x, k):
  if k > x.key:
    error("new key is greater than current key")
  x.key = p
  y = x.p
  if (y is not None) and (x.key < y.key):
    cut(H, x, y)
    cascading_cut(H, y)
  if x.key < H.min.key:
    H.min = x
def cut(H, x, y):
  # remove x from the child list of y
  # decrement y.degree
  # add x to the root list of H
  x.p = None
  x.mark = False
def 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)

摊还代价O(1).

删除一个结点

def fib_heap_delete(H, x):
  fib_heap_decrease_key(H, x, -inf)
  fib_heap_extract_min(H)

摊还时间为O(D(n))即O(lgn).

posted @ 2017-11-29 00:39  AyiStar  阅读(488)  评论(0编辑  收藏  举报