Data structures 完全二叉树作为一种高效的数据结构

Data structures 完全二叉树作为一种高效的数据结构,data-structures,binary-tree,Data Structures,Binary Tree,您将得到一个大小为n的数组(n是2的幂)。数组的所有条目都初始化为零。您必须执行以下一系列联机操作: Add(i,x)将x添加到条目A[i] Reportsum(i,j)=数组中从索引i到j的条目之和。对于任何01)(也称为i/2),第三个数组中的索引(i>>2)(也称为i/4),等等 诀窍在于计算总和(i,j)。我们现在要计算sum(0,j)和sum(0,i-1),因为sum(i,j)=sum(0,j)-sum(0,i-1) 要计算总和(0,v)(对于某些v),您所要做的就是从每个级别最多添加

您将得到一个大小为n的数组(n是2的幂)。数组的所有条目都初始化为零。您必须执行以下一系列联机操作:

  • Add(i,x)
    x
    添加到条目
    A[i]

  • Report
    sum(i,j)
    =数组中从索引
    i
    j
    的条目之和。对于任何
    0
    为了提高效率,我选择了一个数组,其中第一个数组大小为n,下一个数组大小为n/2,n/4,n/8。。。1.无论何时向[i](第一个数组)添加x,都会将其添加到第二个数组中的索引(i>>1)(也称为i/2),第三个数组中的索引(i>>2)(也称为i/4),等等

    诀窍在于计算总和(i,j)。我们现在要计算sum(0,j)和sum(0,i-1),因为sum(i,j)=sum(0,j)-sum(0,i-1)

    要计算总和(0,v)(对于某些v),您所要做的就是从每个级别最多添加一个条目。从0到索引*求和的伪代码(不包括索引本身)如下所示:

    sum from 0 to index:
    begin
        i = 0
        sum = 0
        while i < maxlevel
            if ((index >> i) & 1) != 0
                sum = sum + array[i][index]
        return sum
    end
    
    从0到索引的总和:
    开始
    i=0
    总和=0
    而我却不知道
    如果((索引>>i)&1)!=0
    总和=总和+数组[i][index]
    回报金额
    结束
    
    要直观地了解这一点,请考虑最低级别的数组,并从0求和到偶数索引和奇数索引。如果您使用的是偶数索引,您可以通过使用它上面的数组来更有效地执行此操作,因为它已经将每两个条目相加了!实际上,对于奇数索引,您只需执行与偶数索引相同的操作,只需手动添加一个“奇数人”条目。但是,由于您将在第二个级别对索引进行求和,您可以只做最后一个(如果要求和的新索引是奇数的话)之外的所有操作。。等等等等等等。。这正是我们在这里所做的

    这些应该是你需要的全部了。如果你想用二叉树,你仍然可以用同样的方式。您可以在二叉树的每个节点中保留一个和。在遍历以将和添加到特定节点时,还要将其添加到所遍历的所有节点。同样,您也可以使用查找零索引的相同技巧。查找从零到索引的和现在变成了一个二叉树遍历,其中对于您遍历的每个节点,添加节点的和,然后减去您正在而不是遍历的任何“右侧”(或更高的值)子节点

    希望我没有破坏家庭作业的问题,通过阅读本文,你有足够的兴趣来完成它,但不会太多,问题现在被简单化为仅仅实现

    祝你好运

    树解决方案:

    创建一棵完整的树,它的叶子是你的主菜:1,2,…,n
    node.value=插入值[如果节点是叶]

    node.value=node.left.value+node.right.value[如果节点不是叶子]

    所以,实际上-对于每个子树,其根的值是其所有节点的值之和

    更新主菜是O(logn),因为您需要一直更新到根的总和

    对于sum(i,j),我们将找到i之前所有元素的和,以及j之前所有元素的和,然后从root.value中减去它,我们将得到我们需要的。 因此:

    sumleet()
    sumlright()
    的计算很简单,[对于sumleet:]只需从根开始,一直到下限,每次向左,都要减去right-son值,这样做,就可以从不需要的节点中求和。[说服自己为什么这是真的]。最后,总和只有相关节点。[sumRight的原理相同,但我们会减去left sons]。
    伪代码:

    sumLeft(x,root):
      curr <- root
      sum <- root.value
      while (curr is not a leaf):
          if (x is in curr.right):
             curr <- curr.right
          else:
             sum <- sum - curr.right.value
             curr <- curr.left
      return sum
    sumRight(x,root):
      curr <- root
      sum <- root.value
      while (curr is not a leaf):
          if (x is in curr.left):
             curr <- curr.left
          else:
             sum <- sum - curr.left.value
             curr <- curr.right
      return sum
    
    总结示例:

    总和(4,6)应提供
    4+6+1=11

    sumlefit(4)应提供
    1+3+2=6
    ,并按预期提供:
    sumlefit(4)=21-11-4=6

    sumRight(6)应该提供
    2+2=4
    ,它提供
    sumLeft(6)=21-11-7=4
    。[如预期的那样]
    因此,总的来说:
    sum(4,6)=21-6-4=11
    与预期一致

    添加示例:
    添加(2,4)[将4添加到第二个元素]将导致将树修改为:

                    25
          14                 11
      8        6        7        4
    1  7     2  4     6   1    2   2
    

    我已经为[n]创建了一个段树,其中根包含[I,j],如果我能告诉我如何插入元素,请给出一个10个元素的示例。@rohit:我编辑了解释如何向主菜添加值的答案。注:我不能给出10个元素的例子,因为问题清楚地表明n是2的幂,而10不是。稍后我将能够提供一个包含8个元素的示例树。您已经给出了一个非常好的解决方案,但我认为在您的[code]leftsum(x,root)[/code]和rightsum(x,root)中,如果我将left(x-1,root)right(x+1,root)[请记住,如果x-1n不计算rightsum并将其作为零],那么您的psudo代码工作得非常好。如果我是Worong,请纠正我。@rohit:这是一个伪代码,我调试它不是为了查看所有的边缘情况。但是你提到的似乎是正确的。。。我只给了你一般的指导,要使它成为一个完整的家庭作业解决方案,还需要深入到边缘案例。祝你好运
    add(root,i,x):
      root.value <- root.value + x
      if root is leaf:
          return
      else if i is in root.left:
         add(root.left,i,x)
      else:
         add(root.right,i,x)
    
                    21
          10                 11
      4        6        7        4
    1  3     2  4     6   1    2   2
    
                    25
          14                 11
      8        6        7        4
    1  7     2  4     6   1    2   2