我在理解分段树复杂性方面遇到了问题。很明显,如果你有更新功能只需要改变一个节点,它的复杂性将是log(n)。 但我不知道为什么查询(a,b)的复杂性,其中(a,b)是需要检查的区间,是log(n)。 有人能为我提供直观/正式的证据来理解这一点吗?
答案 0 :(得分:1)
查询间隔(x,y)
时有四种情况FIND(R,x,y) //R is the node
% Case 1
if R.first = x and R.last = y
return {R}
% Case 2
if y <= R.middle
return FIND(R.leftChild, x, y)
% Case 3
if x >= R.middle + 1
return FIND(R.rightChild, x, y)
% Case 4
P = FIND(R.leftChild, x, R.middle)
Q = FIND(R.rightChild, R.middle + 1, y)
return P union Q.
直观地说,前三种情况将树高级别降低1,因为树有高度log n,如果只发生前三种情况,则运行时间为O(log n)。
对于最后一种情况,FIND()将问题分成两个子问题。但是,我们声称这最多只能发生一次。在我们调用FIND(R.leftChild,x,R.middle)之后,我们查询了R.leftChild的区间[x,R.middle]。 R.middle与R.leftChild.last相同。如果x> R.leftChild.middle,然后是案例1;如果x&lt; = R.leftChild,那么我们将调用
FIND ( R.leftChild.leftChild, x, R.leftChild.middle );
FIND ( R.leftChild.rightChild, R.leftChild.middle + 1, , R.leftChild.last );
但是,第二个FIND()返回R.leftChild.rightChild.sum,因此需要花费一些时间,问题不会分成两个子问题(严格来说,问题是分开的,尽管一个子问题需要O(1) )时间解决)。
由于同样的分析适用于R的rightChild,我们得出结论,在case4第一次发生后,运行时间T(h)(h是树的剩余级别)将是
T(h) <= T(h-1) + c (c is a constant)
T(1) = c
产生:
T(h) <= c * h = O(h) = O(log n) (since h is the height of the tree)
因此我们结束了证据。
这是我第一次做出贡献,因此如果有任何问题,请将它们指出,我会编辑我的答案。
答案 1 :(得分:0)
使用段树的范围查询基本上涉及从根节点进行递归。您可以将整个递归过程视为对段树的遍历:任何时候在子节点上需要递归时,您都在遍历中访问该子节点。因此,分析范围查询的复杂性等同于找到所访问节点总数的上限。
事实证明,在任何任意级别上,最多可以访问4个节点。由于段树的高度为log(n),并且在任何级别上最多可以访问4个节点,因此上限实际上是4 * log(n)。因此,时间复杂度为O(log(n))。
现在我们可以用归纳法证明这一点。基本案例位于根节点所在的第一级。由于根节点最多有两个子节点,因此我们最多只能访问这两个子节点,即最多4个节点。
现在,假设在任意级别(例如i级)访问的节点最多为4个,这是事实。我们想表明,我们还将访问下一个级别(i + 1级别)的最多4个节点。如果我们仅在第i层访问了1或2个节点,那么证明在第i + 1层我们将最多访问4个节点是微不足道的,因为每个节点最多可以有2个子节点。
因此,让我们集中在假设在i层访问了3或4个节点的尝试,并尝试证明在i + 1层上,我们最多也可以有4个访问的节点。现在,由于范围查询要求一个连续范围,我们知道在级别i访问的3或4个节点可以分为3个节点分区:最左边的单个节点,其分段范围仅部分查询范围所覆盖的是最右边的单个节点,其段范围仅部分地被查询范围所覆盖; 1个或2个中间节点,其段范围完全被查询范围所覆盖。由于中间节点的段范围完全被查询范围覆盖,因此在下一级别将没有递归;我们只使用它们的预先计算的和。我们在下一级别的最左侧节点和最右侧节点上可能有递归,显然最多为4。
这通过归纳完成了证明。我们已经证明,在任何级别上最多可以访问4个节点。因此,范围查询的时间复杂度为O(log(n))。
答案 2 :(得分:0)
长度为n的间隔可以由k个节点表示,其中k <= log(n)
我们可以根据二进制系统的工作原理来证明这一点。