半路算法之二项树与二项堆
秉承前文。前面提到过针对稀疏图时,以二项堆来作为最小优先队列是更为适宜的。这里记录一下学习二项堆的过程。
二项堆的名字来源于二项树。二项堆是多个二项树连在了一起。
二项树的名字来源于其
Bn
棵树的元素个数为
2n
,且其深度n处恰有
2k
个节点,其性质与二项式非常吻合。此外,它还是一种递归定义的有序树。
重点依照二项式的性质说一下二项树的性质:
首先二项式定理的公式表示为:
嗯,在二项树中我们将上式的a和b统统定位1。
那么二项树的第一个性质—— 共有 2k 个节点,便可以理解为上面二项式的值了;
我们假设 树的高度为r(即画出来的树有r行),在 其深度n处有 Ckn 个节点,其中i=0, 1, 2, …, k,理解为其二项式系数,嗯,刚好等于 Ckn ;
我们假设 根节点(这一行只有它自己,它没有兄弟姐妹节点)的度数为r,它 的度数是这棵二项树上最大的,而且其子女节点分别是它们(子女节点)相对应的子树的根(真有点拗口)
这些性质的证明基本就是二项式定理的证明(数学归纳法,亦即递归)了。这里不再展开。
依据性质1和3,我们知道如果一棵二项树的总结点数为n,那么其节点的最大度数为lgn。
接下来看二项堆。二项堆就是一些二项树把根节点连了起来。它和下一次要讨论的斐波那契堆称为可合并堆,它们支持以下五种操作:
make-heap() --创建并返回一个不包含任何元素的新堆
insert(H, x) --将节点x(有值)插入到堆H中
minimum(H) --返回一个指向堆H中包含最小关键字的节点的指针
extract-min(H) --将堆H中包含最小关键字的节点删除并返回指向该节点的指针
union(H1, H2) --创建并返回一个包含堆H1和H2中所有节点的新堆,同时删除堆H1和H2
二项堆中的每个二项树遵循最小堆的性质,其节点的关键字(即节点的值)大于或等于其父节点的关键字。由于二项堆是有二项树拼起来的,其性质完全就是二项树的那些,不再进一步讨论了。
这里重点说说二项堆的函数实现:
新建一个二项堆
嗯,就是分配并返回了一个对象H,且head[H]=NULL,运行时间为O(1)
寻找最小关键字
伪代码
binomial-heap-minimum(H)
y <- NULL
x <- head[H]
min <- ∞
while x≠NULL
do if key[x]<min
then min <- key[x]
y <- x
x <- sibling[x]
return y
我们需要注意的是关键字只在二项树内排序
代码实现为:
while (x != NULL)
{
if (x.key < min)
{
min = x.key;
y = x;
x = x.sibling;
}
}
return y;
合并两个二项堆
伪代码
binomial-link(y, z)
p[y] <- z
sibling[y] <- child[z]
child[z] <- y
degree[z] <- degree[z]+1
代码实现为:
y.parent = z.child;
z.child = y;
z.degree++;
后面还有合并、插入、取得最小值、去掉最小值、删除某个值的操作。下一篇再写。
另:本篇公式采用MathJax引擎进行了latex公式编写,脚本为:
顺便推荐一下一篇很好的带有常用写法的latex介绍:
一份不太简短的 LATEX 2ε 介绍
星期六, 15. 四月 2017 10:37下午