两个二叉搜索树的幼稚合并的时间复杂性

时间:2018-01-31 16:42:30

标签: algorithm merge time-complexity binary-search-tree asymptotic-complexity

我看到了一个非常短的算法来合并两个二叉搜索树。我很惊讶它是多么简单而且非常低效。但是当我试图猜测它的时间复杂度时,我失败了。

让我们有两个不可变的二进制搜索树(不平衡),它包含整数,你想用伪代码中的下面的递归算法将它们合并在一起。函数insert是辅助函数:

function insert(Tree t, int elem) returns Tree:
    if elem < t.elem:
        return new Tree(t.elem, insert(t.leftSubtree, elem), t.rightSubtree)
    elseif elem > t.elem:
        return new Tree(t.elem, t.leftSubtree, insert(t.rightSubtree, elem))
    else
        return t

function merge(Tree t1, Tree t2) returns Tree:
    if t1 or t2 is Empty:
        return chooseNonEmpty(t1, t2)
    else
        return insert(merge(merge(t1.leftSubtree, t1.rightSubtree), t2), t1.elem)

我猜它是一个指数算法,但我无法找到一个参数。这种合并算法的最差时间复杂度是多少?

2 个答案:

答案 0 :(得分:1)

让我们考虑最差案例:

  

在每个阶段,每棵树都处于 maximally 不平衡状态,即每个节点至少有一个大小为1的子树。

在这种极端情况下,insert的复杂性很容易显示为Ө(n),其中n是树中元素的数量,因为高度为~ n/2

基于上述约束,我们可以推导出merge的时间复杂度的递归关系:

enter image description here

其中n, m的大小为t1, t2。假设不失一般性,右子树总是包含单个元素。这些术语对应于:

  • T(n - 2, 1)merge
  • 子树上对t1的内部调用
  • T(n - 1, m)merge
  • t2的外部电话
  • Ө(n + m):对insert
  • 的最后通话

要解决这个问题,让我们重新替换第一个术语并观察模式:

enter image description here

我们可以通过剥离第一个术语来解决这个问题:

enter image description here

在步骤(*)中,我们使用了变量替换替代i -> i + 1。递归在k = n

时停止

enter image description here

T(1, m)只是将一个元素插入到大小为m的树中,在我们假设的设置中显然是Ө(m)

  

因此merge绝对最差情况时间复杂度为

     

enter image description here

注意:

  • 参数的顺序很重要。因此,通常将较小的树插入较大的树中(以某种方式说)。
  • 实际上,你不太可能在程序的每个阶段都有最大不平衡的树。平均情况自然会涉及半平衡树。
  • 最佳情况(即总是完全平衡的树)要复杂得多(我不确定存在如上所述的分析解决方案;请参阅gdelab的答案)。

编辑:如何评估指数和

假设我们想要计算总和:

enter image description here

其中a, b, c, n是正常数。在第二步中,我们将基数更改为e自然指数常量)。通过此替换,我们可以将ln c视为变量x,区分几何级数,然后设置x = ln c

enter image description here

但几何级数有一个封闭形式的解决方案(标准公式并不难推出):

enter image description here

因此,我们可以将此结果与x n次区分开来,以获得Sn的表达式。对于上面的问题,我们只需要前两个权力:

enter image description here

这个麻烦的术语是由:

enter image description here

这正是Wolfram Alpha直接引用的内容。正如你所看到的,这背后的基本思想很简单,尽管代数非常繁琐。

答案 1 :(得分:0)

准确计算起来相当困难,但看起来它在最坏的情况下并非多项式限制(但这不是一个完整的证明,你需要一个更好的证明):

  • 插入最差的复杂度为O(h),其中h是树的高度(即至少为log(n),可能为n)。

  • merge()的复杂性可以是以下形式:T(n1, n2) = O(h) + T(n1 / 2, n1 / 2) + T(n1 - 1, n2)

  • 让我们考虑F(n) F(1)=T(1, 1)F(n+1)=log(n)+F(n/2)+F(n-1)。我们可能会显示F(n)小于T(n, n)(因为F(n+1)包含T(n, n)而不是T(n, n+1))。

  • 我们有F(n)/F(n-1) = log(n)/F(n-1) + F(n/2) / F(n-1) + 1

  • 假设某些F(n)=Theta(n^k)k。然后F(n/2) / F(n-1) >= a / 2^ka>0 {来自Theta中的常量。

  • 这意味着(超过某一点n0)对于某些固定的F(n) / F(n-1) >= 1 + epsilon,我们总是epsilon > 0,这与F(n)=O(n^k)不兼容,因此矛盾。

  • 所以F(n)不是任何Theta(n^k)的{​​{1}}。直觉上,您可以看到问题可能不是k部分而是Omega部分,因此它可能不是big-O(但从技术上讲,我们在这里使用了O(n)部分获得Omega)。由于a应该比T(n, n)更大, F(n)不应该是多项式,并且可能是指数...

但话又说回来,这根本不严谨,所以也许我真的错了......