如何证明从最小节点在BST中找到后续n-1次是O(n)?
问题是我们可以通过
创建排序顺序1)让节点= BST的最小节点。
2)从该节点开始,我们以递归方式调用find a successor。
我被告知结果是O(n),但我不明白,也不知道如何证明。
不应该是O(n * log n)吗?因为对于步骤1,它是 O(log n),对于步骤2,它也是 O(log n),但它被称为 n- 1次次。因此,它将是 O(n * log n)
请澄清我的疑问。谢谢! :)
答案 0 :(得分:4)
您是正确的,任何个人操作可能需要O(log n)时间,因此如果您执行这些操作n次,您应该获得O(n log n)的运行时。这个界限是正确的,但它不是紧。实际运行时间是Θ(n)。
查看此内容的一种方法是查看树中的任何单个边。如果从最左边的节点开始并重复执行后继查询,您将访问每个边缘多少次?如果仔细观察操作是如何工作的,你会发现每个边缘都被访问了两次:一次向下,一次向上。由于完成的所有工作都是遍历上下边缘,这意味着完成的工作总量与边数的两倍成比例。在任何树中,边数是节点数减1,所以完成的工作总数是Θ(n)。
要将此形式化为证据,请尝试显示您永远不会下降同一个边缘两次,并且当您提升边缘时,您再也不会下降到该边缘。完成此操作后,运行时为Θ(n)的结论将遵循上述逻辑。
希望这有帮助!
答案 1 :(得分:4)
我想发布这篇文章作为对templatetypedef的答案的评论,但它太长了。
他的答案是正确的,因为最简单的方法是看到这是线性的,因为每个边缘都被访问了两次,并且树中的边数总是比节点数少一个(因为每个节点都有一个父,除了根!)。
问题在于,他对正式证据进行短语的方式使用了似乎暗示矛盾的词语。一般来说,数学家不赞成使用矛盾,因为它经常产生含有多余内容的证据。例如:
Proof that 2 + 2 != 5:
Assume for contradiction that 2 + 2 = 5 (<- Remove this line)
Well 2 + 2 = 4
And 4 != 5
Contradiction! (<- Remove this line)
矛盾往往是冗长的,有时它甚至可以模糊证明背后的想法!有时矛盾似乎非常必要,但它相对较少,而且是一个单独的讨论。
在这种情况下,我没有看到矛盾的证据比直接证明更容易。另一方面,无论证明技术如何,这个证明都是正式的丑陋。这是一次尝试:
1)succ(n)
算法遍历两条路径之一
在第一种情况下,从一个节点到其右子树的最左边节点的简单路径上访问每个边
在另一种情况下,节点n
没有正确的孩子,在这种情况下,我们上升其祖先p_1, p_2, p_3, ..., p_k
,使p_(k-1)
是第一祖先< / em>这是它的父母的左孩子。所有这些边缘都在那条简单的路径中被访问
我们希望显示正好在两个succ()
次调用中遍历任意边,一次针对第一种情况succ()
,一次针对第二种情况succ()
。嗯,对于最右边的分支以外的每个边都是如此,但是你可以分别处理这些边缘情况。或者,我们可以证明在访问最后一个元素
这是双重的,因为对于给定的边e
,我们必须找到n1
和n2
,以便succ(n1)
遍历e
和{{ 1}}还遍历succ(n2)
,并证明每个其他e
生成的路径不包含succ()
。
2)首先,我们实际证明,对于e
次访问的每种类型的路径,没有两条路径重叠(即,如果succ()
和succ(n)
都遍历相同类型的路径,那些路径路径没有共享边缘)
在第一种情况下,简单路径精确定义如下。从节点succ(n')
开始,向右移动一边到n
。然后遍历以r
为根的子树的左分支。现在考虑从其他节点r
开始的任何其他此类路径(注意,我们不假设n'
)。它必须在一个节点右转到n != n'
。然后它遍历以r'
为根的子树的最左边分支。如果路径重叠,则选择重叠的一条边。如果它是r'
,那么我们有(n,r) = (n',r')
,因此它是相同的路径。如果它在最左边的分支中有一些n = n'
,那么你可以再次显示e = e'
(你可以追踪最左边的分支并显示每条边是相同的,然后最终得出结论那个n = n'
因为父树是唯一的树。你将在下面看到这个跟踪参数。因此,我们知道对于任何r = r' => n = n'
和n
,如果它们的路径重叠,它们实际上是同一个节点!相反的说法是:如果它们是不同的节点,那么它们的路径不会重叠。这正是我们想要的(并且对立面始终与原始陈述同样如此)。
在第二种情况下,我们定义从节点n'
开始的简单路径并向上移动祖先n
,直到我们到达第一个节点p_1, p_2, ..., p_k = g
,使得{{1} }位于p_k
的左侧。考虑从节点p_(k-1)
开始的同一类型的其他路径p_k
。同样,它访问n'
。因为它是一棵树,所以这些祖先都不会与第一组相同。由于两条路径上的节点都不相同,因此没有一条边可以相同,因此n != n'
和p_1', p_2', ..., p_k' = g'
不会遍历任何相同的边
3)现在我们只需要表明给定边缘至少存在每种类型的一条路径。好吧采取任何这样的边缘succ(n)
(注意这里我忽略了最右边的分支上的特殊边缘,技术上只访问过一次,我也忽略了最左边分支上的特殊边缘,技术上访问过{{1然后一次通过succ(n')
调用)
如果它从左侧小孩e = (c,p)
发送到其父级find_min()
,则succ()
将覆盖第二种类型的路径。要查找其他路径,请继续c
的祖先p
,使succ(c)
位于p
的右侧。根据定义,p_1, p_2, ..., p_k
将遍历包含p_(k-1)
的路径(因为p_k
位于succ(p_k)
的子树的最左边分支上,即e
&#39}正确的孩子)。
当e
是p_(k-1)
的正确子女
总结证明我们已经证明p_k
生成两种类型的路径。对于每种类型的路径,这些类型的所有路径都不重叠。此外,对于任何边缘,我们至少有这些类型的路径中的每一个。由于我们在每个节点上调用c
,我们最终可以得出结论,每个边都被遍历两次(因此算法是p
)。
尽管这个证据有多长,但实际上并没有完成(当我明确表示我正在跳过细节时,甚至忽略了这些要点!)。有些情况下,我说存在的东西没有证明存在。如果你想要的话,你可以弄清楚这些细节,并且实际上让它完全正确是令人满意的(至少在我看来。也许当你是一个天才,你会觉得它很乏味,呵呵)
希望这有帮助。如果您要我澄清一些步骤,请告诉我