跳转至

二项堆

二项堆实际上是一个森林,其中的每一棵树被称为二项树,具有如下性质:

Definition

  1. 一个二项堆中的每棵二项树具有不同的高度;
  2. 高度为 \(0\) 的二项树是一棵单结点树,高度为 \(k\) 的二项树 \(B_k\) 通过将一棵二项树 $B_{k1} 附接到另一棵二项树 \(B_{k−1}\) 的根上而构成;
  3. 每棵二项树都保持堆的序性质,例如是最小堆则根结点最小,孩子都比父亲大。

二项树 \(B_k\) 实际上就是由一个带有儿子 \(B_0, B_1, \ldots, B_{k−1}\) 的根组成。我们很容易根据定义归纳得到高度为 \(k\) 的二项树恰好有 \(2^k\) 个节点,而且在深度 \(d\) 处的节点数恰好就是二项系数 \(\binom{k}{d}\). 每个二项堆也对应着一个唯一的二进制表示,例如 \(13 = 1101\) 对应着 \(B_3, B_2, B_0\) 三棵二项树。

二项堆的操作

Merge

因为二项堆对应着唯一的二进制数,所以合并的操作实际上是将两个二进制数相加,进位的过程就是合并的过程。因为二项树并不是二叉的,所以树的结构使用的是 First-Child Next-Sibling 表示法,并且从左到右子树的高度递减,这样合并的时候就不需要遍历所有的结点,直到最后才能合并。考虑到二进制加法的运算,我们可以得到时间复杂度为 \(O(\log n)\).

FindMin

因为最小值只可能存在于根结点,所以 FindMin 的时间复杂度是 \(O(\log n)\).

DeleteMin

FindMin 以及 Merge 的时间复杂度可知,DeleteMin 的时间复杂度也是 \(O(\log n)\).

Build

我们采取核算法计算二项堆 Build 操作的摊还时间复杂度。因为二进制加法最低位每次 \(+1\) 就会翻转 bit,而次低位两次 \(+1\) 才会翻转 bit,所以 \(n\) 次操作的时间复杂度与

\[ n + \dfrac{n}{2} + \dfrac{n}{4} + \ldots + \dfrac{n}{2^{\lfloor \log n \rfloor} + 1} \]

成正比,所以时间复杂度为 \(O(n)\).