如何证明从最小节点在BST中找到后续n-1次是O(n)?

时间:2013-09-11 00:39:42

标签: algorithm math data-structures big-o binary-search-tree

如何证明从最小节点在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)

请澄清我的疑问。谢谢! :)

2 个答案:

答案 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,我们必须找到n1n2,以便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}正确的孩子)。

  • ep_(k-1)的正确子女

  • 时,类似的论证适用于对称案例

总结证明我们已经证明p_k生成两种类型的路径。对于每种类型的路径,这些类型的所有路径都不重叠。此外,对于任何边缘,我们至少有这些类型的路径中的每一个。由于我们在每个节点上调用c ,我们最终可以得出结论,每个边都被遍历两次(因此算法是p)。

尽管这个证据有多长,但实际上并没有完成(当我明确表示我正在跳过细节时,甚至忽略了这些要点!)。有些情况下,我说存在的东西没有证明存在。如果你想要的话,你可以弄清楚这些细节,并且实际上让它完全正确是令人满意的(至少在我看来。也许当你是一个天才,你会觉得它很乏味,呵呵)

希望这有帮助。如果您要我澄清一些步骤,请告诉我