斐波那契堆

总结:这一章讲了斐波那契堆,它是一种比二项堆更松散的堆,它由一组无序的二项树组成,对不涉及删除元素的操作,它仅需O(1)的平摊运行时间。本章介绍斐波那契堆的插入、合并、删除等操作。

 

1.    斐波那契堆的结构

每个结点x的域:

1)  父节点p[x]

2)  指向任一子女的指针child[x]

3)  左兄弟left[x]

4)  右兄弟right[x]

5)  子女的个数degree[x]

6)  布尔值域mark[x]

 

在斐波那契堆中,结点x的子女被链接成一个环形双链表,称为x的子女表。当left[x]=right[x]=x时,说明x是独子。

 

mark域记录了每个结点的一小段历史:

1)  在某个时刻,x是个根

2)  然后,x被链接到另一个结点上(CONSOLIDATE (FIB-HEAP-LINK) )

3)  再通过切断来去除x的两个子女(CUT, CASCADING-CUT)

一旦第二个孩子失掉了,x与其父节点之间的联系就被切断了,x成为一个新根。如果发生了第1步和第2步,且x的一个孩子被切割掉了,则mark[x]为TRUE。

 

在一个斐波那契堆中,所有树的根都通过用其left和right指针链接成一个环形的双链表,称为该堆的根表。min[H]指向根表中具有最小关键字的结点。n[H]代表H中目前包含的结点个数。

 

势函数:Φ(H) = t(H) + 2m(H),其中t(H)为根表中树的棵树,m(H)为H中有标记的结点的个数。

 

最大度数:结点最大度数的上界D(n)=O(lgn)

 

2.    可合并堆的操作

1)创建

MAKE-FIB-HEAP,分配并返回一个斐波那契堆对象H,且n[H]=0, min[H]=NIL。

实际代价:O(1)

势:Φ(H)=0

平摊代价:O(1)

 

2)插入

插入操作直接将结点插入根表中。

实际代价:O(1)

势的增加:(t(H)+1+2m(H))-(t(H)+2m(H))=1

平摊代价:O(1)+1=O(1)

 

伪代码

FIB-HEAP-INSERT(H,x)

degree[x] <- 0

p[x] <- NIL

child[x] <- NIL

left[x] <- x

right[x] <- x

mark[x] <- FALSE

concatenate the root list containing x with root list H

if min[H]=NIL or key[min[H]] > key[x]

      then min[H] <- x

n[H] <- n[H]+1

 

3)寻找最小结点

min[H]指向最小结点

实际代价:O(1)

势的增加:0

平摊代价:O(1)

 

4)合并

直接将两个堆的根表并置,并确定新的min[H]

实际代价:O(1)

势的增加:0

平摊代价:O(1)

 

伪代码

FIB-HEAP-UNION(H1,H2)

H <- MAKE-FIB-HEAP()

min[H] <- min[H1]

concatenate the root list of H2 with the root list of H

if(min[H]=NIL or key[min[H1]]>key[min[H2]])

      then min[H] <- min[H2]

n[H] <- n[H1]+n[H2]

free the objects H1 and H2

return H

 

5)抽取最小结点

先将最小结点的每个子女都成为一个根,然后将度数相同的根链接起来。注意,直到这里,才真正完成了根表中的树的合并。

实际代价:O(D(n)+t(H))

势的增加:至多(D(n)+1+2m(H))-(t(H)+2m(H))=D(n)-t(H)+1

平摊代价:O(D(n))=O(lgn)

 

伪代码

FIB-HEAP-EXTRACT-MIN(H)

z <- min[H]

if z!=NIL

      then for each child x of z

do add x to the root list of H

                    p[x] <- NIL

            remove z from the root list of H

            if z=right[z]

                 then min[H] <- NIL

                 else min[H] <- right[z]

                       CONSOLIDATE(H)

            n[H] <- n[H]-1

return z

 

CONSOLIDATE(H)将H根表中的度数相同的结点链接起来,直到根表中每个度数至多只有一个根。用到辅助数组A[0…D(n[H])],A[i]=y代表degree[y]=i

伪代码

CONSOLIDATE(H)

for i <- 0 to D(n[H])

      do A[i] <- NIL

for each node w in the root list of H

      do x <- w

         d <- degree[x]

         while A[d]!=NIL

                 do y <- A[d]

                    if key[y]<key[x]

                            then exchange y <-> x

                    FIB-HEAP-LINK(H,y,x)

                    A[d] <- NIL

                    d <- d+1

         A[d] <- x

min[H] <- NIL

for i <- 0 to D(n[H])

      do if A[i]!=NIL

                 then add A[i] to the root list of H

if min[H]=NIL or key[A[i]]<key[min[H]]

                              then min[H] <- A[i]

 

伪代码

FIB-HEAP-LINK(H,y,x)

remove y from the root list of H

make y a child of x, incrementing degree[x]

mark[y] <- FALSE

 

6)减小一个关键字

若结点的关键字减小后,关键字小于其父节点的关键字,则将此结点移出,置入根表中,另外,还需执行级联切断操作。

 

伪代码

FIB-HEAP-DECREASE-KEY(H,x,k)

if k > key[x]

      then error “error”

key[x] <- k

y <- p[x]

if y!=NIL and key[x]<key[y]

      then CUT(H,x,y)

            CASCADING-CUT(H,y)

if key[x]<key[min[H]]

      then min[H] <- x

 

伪代码

CUT(H,x,y)

remove x from the child list of y, decrementing degree[y]

add x to the root list of H

p[x] <- NIL

mark[x] <- FALSE

 

由于CUT使切断的结点的父节点y又失去了一个孩子,因此CASCADING-CUT判断父节点的MARK,若为FALSE,则由于y失去了一个孩子,设mark[y]为TRUE,若mark[y]已经为TRUE了,那么y已经失去了两个孩子了,那么继续切断y与p[y],再接着判断p[y]的MARK,一直沿树递归上去,直到找到一个根节点或未加标记的结点。

 

伪代码

CASCADING(H,y)

z <- p[y]

if z!=NIL

      then if mark[y]=FALSE

                 then mark[y]=TRUE

                 else CUT(H,y,z)

                       CASCADING-CUT(H,z)

 

复杂度分析:

设递归调用了c次CASCADING()

实际代价:O(c)

势的变化:至多(t(H)+c+2(m(H)-c+2))-(t(H)+2m(H))=4-c (c-1个结点被级联切断消除标记,最后一次CASCADING-CUT可能给某个结点加上标记)

平摊代价:O(c)+4-c=O(1)

 

7)删除

平摊代价:O(lgn)

 

伪代码

FIB-HEAP-DELETE(H,x)

FIB-HEAP-DECREASE-KEY(H,x,-INF)

FIB-HEAP-EXTRACT-MIN(H)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值