我看到了一个非常短的算法来合并两个二叉搜索树。我很惊讶它是多么简单而且非常低效。但是当我试图猜测它的时间复杂度时,我失败了。
让我们有两个不可变的二进制搜索树(不平衡),它包含整数,你想用伪代码中的下面的递归算法将它们合并在一起。函数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)
我猜它是一个指数算法,但我无法找到一个参数。这种合并算法的最差时间复杂度是多少?
答案 0 :(得分:1)
让我们考虑最差案例:
在每个阶段,每棵树都处于 maximally 不平衡状态,即每个节点至少有一个大小为1的子树。
在这种极端情况下,insert
的复杂性很容易显示为Ө(n)
,其中n
是树中元素的数量,因为高度为~ n/2
基于上述约束,我们可以推导出merge
的时间复杂度的递归关系:
其中n, m
的大小为t1, t2
。假设不失一般性,右子树总是包含单个元素。这些术语对应于:
T(n - 2, 1)
:merge
t1
的内部调用
T(n - 1, m)
:merge
t2
的外部电话
Ө(n + m)
:对insert
要解决这个问题,让我们重新替换第一个术语并观察模式:
我们可以通过剥离第一个术语来解决这个问题:
在步骤(*)
中,我们使用了变量替换替代i -> i + 1
。递归在k = n
:
T(1, m)
只是将一个元素插入到大小为m
的树中,在我们假设的设置中显然是Ө(m)
。
因此
merge
的绝对最差情况时间复杂度为
注意:
gdelab
的答案)。编辑:如何评估指数和
假设我们想要计算总和:
其中a, b, c, n
是正常数。在第二步中,我们将基数更改为e
(自然指数常量)。通过此替换,我们可以将ln c
视为变量x
,区分几何级数,然后设置x = ln c
:
但几何级数有一个封闭形式的解决方案(标准公式并不难推出):
因此,我们可以将此结果与x
n
次区分开来,以获得Sn
的表达式。对于上面的问题,我们只需要前两个权力:
这个麻烦的术语是由:
这正是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^k
为a>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)
不应该是多项式,并且可能是指数...
但话又说回来,这根本不严谨,所以也许我真的错了......