斐波那契堆支持的操作有:
在不设计删除元素的操作仅需O(1)的平摊时间。
在实际情况中,斐波那契堆的常数因子以及程序上设计的复杂性,使得它没有二叉(或k叉)堆合适。因此,斐波那契堆主要具有理论上的意义。
斐波那契堆不能支持search操作,所以对于一些定点操作需要将结点指针作为输入的一部分。
斐波那契堆的结构
斐波那契堆由一组最小堆有序树组成,这里的有序仅仅是指根是树中最小的元素,其他不保证。
每个结点都有4个指针
如果没有左右兄弟的话,相应的左右兄弟指针都指向自身。没有父子结点的话相应指针则为nil。 这也说明在相同高度的结点形成了一个双向链表,这样去掉一个结点以及合并两个表都可以在O(1)时间内完成。
每个结点还有其他两个域:
另外斐波那契堆还有两个值
势函数
采用势能方法来分析斐波那契堆的性能,对于一个给定的斐波那契堆H,t(H)表示堆中树的颗数,m(H)表示有标记的结点个数(结点的mark值为true),势定义为:
f(H) = t(H) + 2m(H)
最大度数
D(n) = O(lgn)
可合并堆的操作
对斐波那契堆上各种操作来说,关键思想是尽量把工作推后。
如果想要一次extract-min操作代价小,那么堆中的树的数目要尽量可能的少,为了保证这一点,要付出一定代价,例如可能要花lgn时间插入一个结点或者合并两个堆。
实际实现还是在extract-min时候做一些耗时工作。
创建一个斐波那契堆
只是生成一个空的堆对象H,代价为O(1),势为0。
插入一个结点
增加的势只有一个多一颗树,为1。
合并两个堆
合并两个堆仅仅将跟表合并,然后将最小值的指针指向原来两个堆中的最小值中较小的那一个。
势没有发生改变。
抽取最小结点
在循环合并根表的过程中,总共有原先的 t(H) + 原先最小结点的孩子数D(n) - 原先最小结点1 颗树,每棵树最多只会成为其他树的子树一次。
所以循环的代价为t(H) + D(n) - 1。
势的变化最多为原先最小结点孩子全部都成为新树D(n) 。
总代价为 t(H) + D(n) - 1 + D(n) = O(D(n))。
减小一个关键字
删除一个结点
有了上面的两个操作,删除一个结点很简单。
最大度数的届
要证明上面的抽取最小结点的操作代价为lg(n),那就要证明D(n)为O(lg(n))。