跳转至

第 4 周:左偏树和斜堆

左偏树

Null 路径长度

Npl(x) 代表从 x 往下到它的最近的 null 结点所需要的路程。Npl(null) = 1。

性质

  • 如果一棵左偏树从根一直往右走的路径上面有 r 个结点,那么这棵树最少有 \(2^r - 1\) 个结点。
  • 相应的,一个结点数为 N 的左偏树的右路径最长是 \(\lfloor \log (N + 1) \rfloor\)

斜堆

这是一个均摊时间复杂度 \(O(M \log N)\) 的东西,N 是结点个数,M 是操作数。

和左偏树的区别是并不维护 Npl。合并的时候总会交换左右儿子。

摊还分析

现在要进行 n 次合并操作,最终最多有 n 个结点(每次都插入)。

  • 重结点是右子树结点数量大于左子树结点数量的结点,其他结点叫做轻结点。
  • 势能 \(\Phi(i)\) 是第 i 次合并后重结点的数量;很明显 \(\Phi(i) < n\)

现在是第 i 次合并,需要合并两个堆 a 和 b。它们右路径上面轻、重结点个数分别是 \(l_a, h_a, l_b, h_b\)。(合并时只有右路径上的结点轻重状态可能变化。)

这一次合并的实际开销是 \(c_i = l_a + h_a + l_b + h_b\)

合并后所有的重结点都会变成轻结点。最坏情况是所有的轻结点都变成重结点。注意此时一条右路径上的轻结点的数量小于 \(\log n\)(右子堆结点数小于等于左子堆结点数)。

所以势能变化是 \(\Delta \Phi \leq l_a + l_b - h_a - h_b\)

\[\begin{aligned} \hat{c_i} & = \Delta \Phi + c_i \\ & \leq 2 (l_a + l_b) \\ & \leq 2 \log n \end{aligned}\]

那么 n 次的均摊开销是

\[\begin{aligned} \sum_{i=1}^{n}{c_i} + \Phi(n) - \Phi(0) & = \sum_{i=1}^{n}{\hat{c_i}} \\ \sum_{i=1}^{n}{c_i} + \Phi(n) - \Phi(0) & \leq 2 n \log n \\ \sum_{i=1}^{n}{c_i} & \leq n + 2n \log n \end{aligned}\]

就是这样。