左式堆将插入、合并和删除最小元的操作控制在O(logN),尽管时间已经够少了,但二项队列进一步降低了这个时间。二项队列(binomial tree)以最坏时间O(logN)支持以上操作,并且插入操作平均花费常数时间。
二项队列不是一棵树,而是树的集合,称为森林,这里的树有特定的形式,同时也具有堆序性,叫做二项树(binomial tree)。如图为一个二项队列,有B0,B1,B2,B3,B4五棵二项树。可以看到,二项队列具有以下特性:
1、高度为k的二项树Bk通过将高度为Bk-1的二项树接到另外一棵高度为Bk-1的二项树的根上构成。
2、二项树Bk由一个带有儿子B0,B1·····Bk-1的根组成(形状上),从Bk的构成过程可以知道这个特性,在构成B3的过程中,经历了根节点接上B0,B1,B2的过程。
3、高度为k的树有2^k个节点,第k棵树的节点会等于第k-1棵树的节点*2,那么B0,B1,B2的节点数就是这样子往后推。
4、对于每个Bk,深度d处的节点数为二项系数.
在这种结构中如何存储数据呢?如图,6个元素存储在二项树中,6=0110,对应B1,B2。第i棵二项树有2^i个节点,这与二进制不谋而合,第i棵二项树的对应二进制的第i位。二项队列中的每棵树都要满足堆序性,如下图。
二项队列的操作主要有插入,合并,删除最小元,插入的操作可以看成只有单个节点的二项队列和另一个二项队列的合并。合并操作中很重要的部分是合并两棵高度相等的树。二项树具有多个孩子节点,我们用一般树的表示方法:每个节点的儿子都存在一个链表中,每个节点都有一个指向他的第一个儿子和第一个兄弟的指针。为了操作简单,二项树的子树采用递减的顺序(二项队列存储二项树仍是按照高度递增排序的)。因为新的子树将会是最大的子树,将它作为第一个儿子比将它作为最后一个儿子(要遍历孩子链表将新的子树放在链表末尾)更加方便。
struct N