您的位置:首页 > 其它

算法导论学习笔记-第十九章-二项堆

2010-08-07 18:57 295 查看
第十九章 二项堆

总结:这一章介绍了二项树、二项堆,并介绍了二项堆的搜索、删除、插入等操作,二项堆比二叉堆的优势就是二项堆的合并的复杂度只有O(lgn),而二叉堆合并的复杂度在最坏情况下有O(n),因此若进行合并操作,二项堆的性能就比二叉堆要好了。

1. 二项树
一个二项堆由一组二项树构成。
二项树是一种递归定义的有序树,二项树B0只包含一个结点,二项树Bk由两颗二项树Bk-1链接而成:其中一颗树的根是另一棵树的根的最左孩子

二项树Bk的性质:
1) 共有2k个结点
2) 树的高度为k
3) 在深度i处恰有Cik个结点
4) 根的度数(子女的个数)为k,它大于任何其他结点的度数;如果根的子女从左到右的编号设为k-1, k-2, …, 0,子女i是子树Bi的根。

2. 二项堆
二项堆由一组二项树组成,二项堆H满足性质:
1) H中的每个二项树都遵循最小堆性质:结点的关键字大于等于其父节点的关键字。因此,根的关键字最小
2) 对任意非负整数k,在H中至多有一棵二项树的根具有度数k。(即至多有一棵二项树Bk,事实上,若H中有n个结点,n的二进制表示为blogn,…,b0,那么当且仅当bi=1时,二项树Bi存在于H中)


二项堆中结点x的表示:
1) 父结点p[x]
2) 最左孩子child[x]
3) 紧右兄弟sibling[x]
4) 度degree[x]
5) 关键字key[x]
一个二项堆中各二项树的根被组织成一个链表,称之为根表。

3. 二项堆的操作
1) 创建新二项堆
MAKE-BINOMIAL-HEAP分配并返回一个对象H,且head[H]=NIL
复杂度:O(1)

2) 寻找最小关键字
遍历根表,找出根表中关键字最小的结点。
复杂度:O(lgn)

伪代码

BINOMIAL-HEAP-MINIMUM(H)

y <- NIL
x <- head[H]
min <- INF
while x!=NIL
do if key[x] < min
then min <- key[x]
y <- x
x <- sibling[x]
return y

3) 合并
连接操作,即将两棵根节点度数相同的二项树Bk-1连接成一棵Bk
复杂度:O(1)

伪代码

BINOMIAL-LINK(y,z)

p[y] <- z
sibling[y] <- child[z]
child[z] <- y
degree[z] <- degree[z]+1

合并操作分为两个阶段:
第一阶段执行BINOMIAL-HEAP-MERGE,将两个堆H1和H2的根表合并成一个按度数的单调递增次序排列的链表。MERGE的时间复杂度O(logn)。n为H1和H2的结点总数。

第二阶段将相等度数的根连接起来,直到每个度数至多有一个根时为止。执行过程中,合并的堆H的根表中至多出现三个根具有相同的度数。(MERGE后H中至多出现两个根具有相同的度数,但是将两个相同度数的根的二项树连接后,可能与后面的至多两棵二项树出现相同的度数的根,因此至多出现三个根具有相同的度数)
第二阶段根据当前遍历到的根表中的结点x,分四种情况考虑:
Case1:degree[x]!=degree[sibling[x]]。此时,不需要做任何变化,将指针向根表后移动即可。
Case2:degree[x]=degree[sibling[x]]=degree[sibling[sibling[x]]]。此时,仍不做变化,将指针后移。
Case3 & Case4:degree[x]=degree[sibling[x]]!=degree[sibling[sibling[x]]] 且
Case3:key[x]<=key[sibling[x]]。此时,将sibling[x]连接到x上。
Case4:key[x]>key[sibling[x]]。此时,将x连接到sibling[x]上。
复杂度:O(logn)

伪代码

BINOMIAL-HEAP-UNION(H1,H2)

H <- MAKE-BINOMIAL-HEAP()
head[H] <- BINOMIAL-HEAP-MERGE(H1,H2)
free the objects H1 and H2 but not the lists they point to
if head[H]=NIL
then return H
prev-x <- NIL
x <- head[H]
next-x <- sibling[x]
while next-x!=NIL
do if (degree[x]!=degree[next-x]) or (sibling[next-x]!=NIL and
degree[x]=degree[sibling[next-x]])
then prev-x <- x
x <- next-x
else if key[x]<=key[next-x]
then sibling[x] <- sibling[next-x]
BINOMIAL-LINK(next-x,x)
else if prev-x=NIL
then head[H] <- next-x
else sibling[prev-x] <- next-x
BINOMIAL-LINK(x,next-x)
x <- next-x
next-x <- sibling[x]
return H

4) 插入
先构造一个只包含一个结点的二项堆,再将此二项堆与原二项堆合并
复杂度:O(logn)

伪代码

BINOMIAL-HEAP-INSERT(H,x)

H’ <- MAKE-BINOMIAL-HEAP()
p[x] <- NIL
degree[x] <- 0
child[x] <- NIL
sibling[x] <- NIL
head[H’] <- x
H <- BINOMIAL-HEAP-UNION(H,H’)

5) 抽取具有最小关键字的结点
从根表中找到最小关键字的结点,将以该结点为根的整棵二项树从堆取出,删除取出的二项树的根,将其剩下的子女倒序排列,组成了一个新的二项堆,再与之前的二项堆合并。
复杂度:O(logn)

伪代码

BINOMIAL-HEAP-EXTRACT-MIN(H)

find the root x with the minimum key in the root list of H
and remove x from the root list of H
H’ <- MAKE-BINOMIAL-HEAP()
reverse the order of the linked list of x’s children, setting the p field of each child to NIL and set head[H’] to point to the head of the resulting list
H <- BINOMIAL-HEAP-UNION(H,H’)
return x

6) 减小关键字的值
复杂度:O(logn)

伪代码

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

if k > key[x]
then error “error”
key[x] <- k
y <- x
z <- p[y]
while z!=NIL and key[y] < key[z]
do
exchange key[y] <-> key[z]
y <- z
z <- p[z]

7) 删除
复杂度:O(logn)

伪代码

BINOMIAL-HEAP-DELETE(H,x)

BINOMIAL-HEAP-DECREASE-KEY(H,x,-INF)
BINOMIAL-HEAP-EXTRACT-MIN(H)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: