AVL tree 高度上下界推导

1. 最大高度对应 Node 数量 \(N_{h}\) 的递归公式

设有一棵 AVL tree 的高度为 \(h\), 对于该树, 构成该树的最少 node 数量为 \(N_{h}\) .
有: 最坏情况下, root 的两棵 subtree 高度为 \(h-1\)\(h-2\) .
因此得到以下公式 (其中 \(h \in N^{+}\)):

\[N_{h}= \begin{cases} 0 &h=0 \\ 1 &h=1 \\ N_{h-1}+N_{h-2}+1 &h\geq2 \end{cases} \]

2. 证明 \(N_{h}=Fibonacci_{(h+2)}-1\)

2.1. 方法 1 - 数学归纳法

已知:

\[\begin{aligned} N_{h}&=\begin{cases}0 &h=0 \\ 1 &h=1 \\ N_{h-1}+N_{h-2}+1 &h \geq 2 \end{cases}\\ ~\\ F_{h}&=F_{h-1}+F_{h-2}~~h\geq2 \end{aligned} \]

且有:

\[N_{0}=F_{2}-1\\ N_{1}=F_{3}-1 \]

假设:

\[N_{k}=F_{k+2}-1,~N_{k+1}=F_{k+3}-1~~k \in N^{+}~且~k\geq3 \]

则:

\[\begin{aligned} N_{k+2}&=N_{k}+N_{k+1}+1\\ &=F_{k+2}-1+F_{k+3}-1+1\\ &=F_{k+4}-1 \end{aligned} \]

假设成立.

2.2. 方法 2 - 直接推导

\(h \geq 2\) 由:

\[\begin{aligned} &N_{h} = N_{h-1}+N_{h-2}+1 \\ \Rightarrow & N_{h}+1=(N_{h-1}+1)+(N_{h-2}+1) \end{aligned} \]

并且当 \(h=1\)\(h=2\) 时, \(N_{h}=Fibonacci_{(h+2)}-1\) 也成立.
综上:

\[N_{h}=Fibonacci_{(h+2)}-1 \]

3. \(N_{h}\) 的通项公式以及 h 的解和渐进记法

已知 Fibonacci sequence 的通项公式为:

\[F_{n}=\frac{1}{\sqrt{5}}\bigg[\bigg(\frac{1+\sqrt{5}}{2}\bigg)^n - \bigg(\frac{1-\sqrt{5}}{2}\bigg)^n\bigg] \]

\(n=N_{h}\) , 根据 2.2 的证明, 得到:

\[n=\frac{1}{\sqrt{5}}\bigg[\bigg(\frac{1+\sqrt{5}}{2}\bigg)^{h+2} - \bigg(\frac{1-\sqrt{5}}{2}\bigg)^{h+2}\bigg]-1 \\~\\ \]

  • \(h\) 为偶数,
    \(y=\big(\frac{1+\sqrt{5}}{2}\big)^{h+2}\) , 则 \(\big(\frac{1-\sqrt{5}}{2}\big)^{h+2}=y^{-1}\) , 代入上式得到:

    \[\begin{aligned} &y^2-\sqrt{5}(n+1)y-1=0 \\ \Rightarrow~ &y=\frac{\sqrt{5}(n+1)+\sqrt{5(n+1)^2+4}}{2} \end{aligned} \]

    进而求出

    \[\begin{aligned} h&=-2+\log_{[(\sqrt{5}+1)/2]}{\frac{\sqrt{5}(n+1)+\sqrt{5(n+1)^2+4}}{2}} \\ &=-2+\frac{\ln{\big[~\sqrt{5}(n+1)+\sqrt{5(n+1)^2+4}~\big]}-\ln{2}}{\ln{(\sqrt{5}+1)}-\ln{2}} \\ &=O(\log{n}) \end{aligned} \]

  • \(h\) 为奇数,
    \(y=\big(\frac{1+\sqrt{5}}{2}\big)^{h+2}\) , 则 \(\big(\frac{1-\sqrt{5}}{2}\big)^{h+2}=-y^{-1}\) , 代入上式得到:

    \[y=\frac{\sqrt{5}(n+1)+\sqrt{5(n+1)^2-4}}{2} \]

    进而求出:

    \[ \begin{aligned} h&=-2+\frac{\ln{\big[~\sqrt{5}(n+1)+\sqrt{5(n+1)^2-4}~\big]}-\ln{2}}{\ln{(\sqrt{5}+1)}-\ln{2}} \\ &=O(\log{n}) \end{aligned} \]

4. C++求解

4.1. 直接公式法

在 3 中, 我们得出了以下公式 ( \(\pm\) 的确定取决于 \(h\) 的奇偶):

\[h=-2+\frac{\ln{\big[~\sqrt{5}(n+1)+\sqrt{5(n+1)^2 \pm 4}~\big]}-\ln{2}}{\ln{(\sqrt{5}+1)}-\ln{2}} \]

为了简便运算, 我们可以将上式改为:

\[\begin{aligned} h&=-2+\frac{\ln{\big[~\sqrt{5}(n+1)+\sqrt{5(n+1)^2 \pm 4}~\big]}}{\ln{(\sqrt{5}+1)}-\ln{2}}-\frac{\ln{2}}{\ln{(\sqrt{5}+1)}-\ln{2}} \\ &<-3.44042+\frac{\ln{\big[~\sqrt{5}(n+1)+\sqrt{5(n+1)^2 \pm 4}~\big]}}{0.48121} \end{aligned} \]

将上式写为程序, 函数名为 heightOfAVL_formula , 参数 numOfNode 传入 node 数量, 返回能够构成的 AVL tree 的最大高度:

#include <cmath>

constexpr double sqrt5 = 2.23606797749979;
constexpr double down512 = 0.4812118250596034;
constexpr double left2L2 = -3.440420090412556;

inline size_t heightOfAVL_formula(size_t numOfNode)
{
    numOfNode++;
    size_t h = left2L2 + log(sqrt5 * (numOfNode + 1) + sqrt(5 * numOfNode * numOfNode - 4.0)) / down512;
    if (h & 1) {
        return h;
    } else {
        return left2L2 + log(sqrt5 * numOfNode + sqrt(5 * numOfNode * numOfNode + 4.0)) / down512;
    }
}

理论上说, 当 node 数量极大, 公式法能够提供良好的性能.
尽管当 \(h\) 为偶数, 需要多进行一次计算,
但是对于任意 node 数量, 只需平均计算 1.5 次.
然而计算本身的效率较低, 同时运算中浮点数产生的误差可能难以估计 (事实上对 47000 个 node 已经给出了错误解).

4.2. 利用 Fibonacci sequence 间接求解

根据 2 中证明的 \(N_{h}=Fibonacci_{(h+2)}-1\) ,
函数 heightOfAVL_iteration 利用迭代更优雅地求解了 AVL tree 的高度.

inline size_t heightOfAVL_iteration(size_t numOfNode)
{
    if (numOfNode == 0) return 0;
    size_t arr[2] = { 2,3 };
    size_t height = 4;
    while (true) {
        if (arr[0] - 1 <= numOfNode && arr[1] - 1 > numOfNode) { return height - 3; }
        arr[0] = arr[1] + arr[0];
        std::swap(arr[0], arr[1]);
        height++;
    }
}

上述方法效率更高, 而且无需担心运算中的精度损失.

5. 鸣谢

lrf8182


Reference | Data Structures, Algoritms, and Applications in C++, Sartaj Sahni

posted @ 2022-08-06 19:43  JamesNULLiu  阅读(229)  评论(0编辑  收藏  举报