计算二叉树的单个垂直线中的节点总和

时间:2011-05-11 06:25:49

标签: array-algorithms

对于二叉树,我想得到落在单个垂直线上的所有节点的总和。我想要每个Verticle节点中的节点总和

             A
           /    \
          B      C
         /  \   /  \
         D   E  F   G
        / \ 
        H  I

如果你看看上面的发球台

line 0   A  E F   so sum  = A+E+F
line -1  B I      so sum = B +I
line 1   C        so sum = C
line 2   G        so sum = G

我实现了以下算法

Map<Integer,Integere> mp = new HashMap<Integer,Integer>()
calculate(root,0); 

 void calculate(Node node, int pos){
   if(node==null)
        return ;
  if(mp.containsKey(pos) ){
    int val = mp.get(pos) + node.data;
     mp.put(pos,val);
    }
    else{ 
         mp.put(pos,node.data);
    }

    calculate(node.left,pos-1);
    calculate(node.right,pos+1);

}
  1. 我认为上面的算法很好。可以 任何一个确认?
  2. 另外,我怎么能不使用 HashMap,arraylist或任何此类 java.One的集合数据类型 方法是两个是2个数组一个 存储负面索引(映射到 积极的)和积极的 索引(根的右侧)。但是我们 不知道数组的大小 将是。
  3. 一种方法是使用双向链接 列表并在右/左添加节点 必要时运动。不是 我怎么能实现这个 进场?任何其他简单/更多的时间 有效的方法?
  4. 是上述代码的复杂性 我推论是O(n)? (我不擅长 分析时间复杂度,所以 问)

4 个答案:

答案 0 :(得分:2)

您可以在深度优先顺序中访问二叉树,并使用偏移量来跟踪您相对于起始节点向左/右移动的距离。每次向左移动时,都会减小偏移量,每次向右移动都会增加偏移量。如果调用的访问过程的偏移量为0,则表示被访问的节点与起始节点的偏移量相同(即它位于同一列中),因此必须添加其值。 / p>

伪代码:

procedure visit (node n, int offset) {
  sumleft = 0
  sumright = 0
  if (n.left != null)
    sumleft = visit(n.left, offset - 1)
  if (n.right != null)
    sumright = visit(n.right, offset + 1)
  if (offset == 0)
    return n.value + sumleft + sumright
  else
    return sumleft + sumright;
}

例如,如果你打电话

visit(A, 0)

您将收到以下电话:

visit(A, 0) -> E.value + F.value + A.value
  visit(B, -1) -> E.value
    visit(D, -2) -> 0
      visit(H, -3) -> 0
      visit(I, +2) -> 0
    visit(E, 0) -> E.value
  visit(C, +1) -> F.value
    visit(F, 0) -> F.value
    visit(G, +1) -> 0

另一个例子,从节点B开始:

visit(B, 0)
  visit(D, -1) 
    visit(H, -2)
    visit(I, 0) -> here we return I.value
  visit(E, +1)

当递归返回到初始调用visit(B, 0)时,我们有sumleft = I.valuesumright = 0,因此我们会按预期返回最终结果B.value + I.value

O(n)的复杂性,因为一旦树的所有节点都以起始节点为根,您就会访问它。


在考虑上述算法之后,我意识到它有一个限制,当我们考虑如下的更复杂的树时,这种限制变得明显:

tree columns

在这种情况下,visit(B, 0)仍会返回B.value + I.value,但这不是预期的结果,因为N也在同一列上。以下算法应该解决这个问题:

procedure visit(node n, int c, int t) {
  sumleft = 0;
  sumright = 0;
  if (n.left != null)
    sumleft = visit(n.left, c - 1, t)
  if (n.right != null)
    sumright = visit(n.right, c + 1, t)
  if (c == t)
    return n.value + sumleft + sumright;
  else
    return sumleft + sumright;
}

这个想法基本相同,但我们现在有一个参数c,它给出了当前列,参数t是目标列。如果我们想要B列中元素的总和,那么我们可以调用visit(A, 0, -1),也就是说我们总是从节点A(根树)开始我们的访问,它位于第0列,我们的目标是第-1列。我们得到以下信息:

tree columns calls

因此visit(A, 0, -1) = B + I + N符合预期。

复杂度始终为O(n),其中n是树中节点的数量,因为我们使用深度优先后序访问整个树,并且我们只处理每个节点一次。


如果我们想要计算每列的总和,我们可以使用以下算法

procedure visit(node n, int c) {
  if (n.left != null)
    S{c} += n.value;
    visit(n.left, c - 1)
    visit(n.right, c + 1)
}

并调用visit(A, 0),其中A是根节点。请注意,算法中的S{...}是一个映射,其键是列数(..., - 2,-1,0,1,2,...)及其值(在算法结束时) )是该列中节点值的总和(S{1}将是第1列中节点的总和)。如果我们注意索引(数组没有负索引),我们也可以使用数组而不是映射。算法仍然是O(n),因为我们只遍历整个树一次。但是,在这种情况下,我们需要额外的空间来存储所有列(地图或数组)的总和。如果我没弄错,高度为h的二叉树将会有2*h + 1列。

答案 1 :(得分:2)

C ++代码

int vertsum(Node* n, int cur_level, int target_level)
{
  if (!n)
    return 0;

  int sum = 0;
  if (cur_level == target_level)
    sum = n->value;
  return sum + 
         vertsum(n->left, cur_level-1, target_level) + 
         vertsum(n->right, cur_level+1, target_level);
}

调用示例:

vertsum(root, 0, 1);

修改

在澄清要求之后,这里是建议的代码。请注意,这是C ++'ish,并不完全使用Java或C ++的标准API列表,但你应该明白这一点。我假设addNodeBeforeaddNodeAfter初始化节点的数据(即ListNode::counter

void vertsum(TreeNode* n, int level, ListNode& counter)
{
  if (!n)
    return;

  counter.value += n->value;
  counter.index = level;

  if (! counter.prev)
    addNodeBefore(counter);
  vertsum(n->left, level-1, counter.prev);             

  if (! counter.next)
    addNodeAfter(counter);
  vertsum(n->right, level+1, counter.next);

  return;
}

答案 2 :(得分:0)

以下怎么样? (在节点类中,假设getData返回整数值,hasRight()和hasLeft()是布尔值,指示是否存在右/左分支,getRight()和getLeft()返回右/左分支中的下一个节点。

public int calculateVerticalLine(int numLine) {
    return calculateVerticalLineRecursive(numLine, 0);
}

protected int calculateVerticalLineRecursive(int numLine, int curPosition) {
    int result = 0;
    if(numLine == curPosition) result += this.getData();
    if(hasRight()) result += getRight().calculateVerticalLineRecursive(numLine, curPosition+1);
    if(hasLeft()) result += getLeft().calculateVerticalLineRecursive(numLine, curPosition-1);
    return result;
}

答案 3 :(得分:0)

public class Solution {

    public static int getSum(BinaryTreeNode<Integer> root) {
        //Your code goes here.
        if(root==null){
            return 0;
        }
       int leftnodesum=getSum(root.left);
       int rightnodesum=getSum(root.right);

    
    return root.data+leftnodesum+rightnodesum;
    }
}