【问题标题】:Binary Tree branch sums without recursion无递归的二叉树分支求和
【发布时间】:2020-02-22 05:54:44
【问题描述】:

我试图在不使用递归的情况下计算二叉树每个分支的总和。我正在尝试使用堆栈,但无法弄清楚如何修复我的代码以获得正确的总和。

public static List<Integer> branchSums(BinaryTree root) {
    LinkedList<BinaryTree> toVisit = new LinkedList<>();
    BinaryTree current = root;
    List<Integer> sums = new ArrayList<>();
    int sum = 0;

    while (current != null || !toVisit.isEmpty()) {
        while (current != null) {
            sum += current.value;
            toVisit.push(current);
            current = current.left;
        }

        current = toVisit.pop();

        // if found leaf add sum to results and decrement sum by current node
        if (current.left == null && current.right == null) {
            sums.add(sum);
            sum -= current.value;
        }

        current = current.right;
    }

return sums;
}

示例输入:

         1
      /      \
     2        3
   /   \    /   \
  4     5  6     7
 / \   /
8   9 10

示例输出 [15, 16, 18, 10, 11]

【问题讨论】:

  • 你能举一个树的例子和预期的输出吗?问题不清楚,因为您的代码没有反映答案,所以问题不清楚
  • 您应该做的第一件事是在循环的开头写一个注释,描述此时应该在堆栈上的内容,以及应该在sum 中的节点,以及什么是剩下要做的。然后确保每次迭代都是如此。

标签: java algorithm data-structures binary-tree


【解决方案1】:

您的代码的问题是您没有跟踪哪个节点 上次从您的堆栈中弹出。

这是更新后的代码:

public static List<Integer> caculateSum(BinaryTree root) {
    List<Integer> sums = new ArrayList<>();
    int sum=0;
    BinaryTree current = root, popped=null;
    Stack<BinaryTree> s = new Stack<BinaryTree>();
    while(current!=null ) {
        //checking if last node popped from stack is not equal to left or right node of current node
        if(popped==null||((current.left!=null && !current.left.equals(popped)) && (current.right!=null && !current.right.equals(popped)))) {
            while(current != null) {
                sum+=current.value;
                s.push(current);
                current = current.left;

            }
        }
        current=s.peek();
        if(current.right == null) {
            //if current node is leaf node
            if(current.left == null) {
                sums.add(sum);
            }
            sum-=current.value;
            popped = current;
            s.pop();
        } else if(current.right!=null && current.right.equals(popped)){
            //if current node both left and right nodes have been processed
            sum-=current.value;
            popped = current;
            s.pop();
        }else {
            //if current node right part is not processed
            sum+=current.right.value;
            s.push(current.right);  
        }
        if(s.isEmpty()) {
            break;
        }
        current=s.peek();       
    }   
    return sums;
}

将通过一个例子来解释这一点。假设我们给了二叉树

1,2,9,3,7,null,8,5

在上面的代码中,除了旧变量之外,还使用了一个新变量popped,它跟踪从堆栈中弹出的最后一个元素

所以,以下是主要步骤:

  1. 首先从current节点开始,我们检查当前节点left是否不等于popped(如果相等则意味着currentnode left部分已经被处理,所以我们不需要再次处理) .同样,我们正在检查current 节点右节点是否不等于popped 节点(如果相等则意味着我们已经处理了current 节点的右节点,这间接意味着left 节点也被处理)。
  2. 现在我们检查堆栈的顶部节点 current 节点:

    • 如果它的right 节点为空 如果为真,则表示current 节点是叶节点或者它是一个已经处理的节点,其right 节点为空(如我们的示例节点中值为 3)。如果是 叶我们将它添加到我们的sums 列表中。此外,对于这两种情况,我们删除 这个top 节点并从当前sum 值中减去它的值 (这件事也已经在上面的代码中完成了)。除此之外,我们 将在popped 变量中跟踪堆栈中弹出的元素。

    • 如果它的右不为空但它的right节点等于popped 节点这发生在我们处理的最后一次while循环中 这个right 节点。这意味着对于堆栈的顶部节点,左侧和 正确的节点已被处理,因此我们弹出该节点并保留 在popped 变量中跟踪它。

    • 否则我们将栈顶元素的右节点压入栈中。

在上述示例的最后,sums 变量会将结果存储为 [11, 10, 18]

【讨论】:

  • 你的代码导致无限循环,但我会考虑弹出的想法并在我的代码中尝试一下
  • 您尝试了哪个示例,因为我已经检查了上面的示例并且效果很好。
【解决方案2】:

我尝试这个是为了好玩,但很惊讶我没有看到任何实际的解决方案。以下是在 Kotlin 中,但可以很容易地转录成 Java。诀窍是在弹出节点之前将状态添加到节点本身以将其标记为已使用,否则在进入另一个分支时没有任何值可检查。

这在极少数情况下可能对防止堆栈溢出有用吗?这仍然会在 O(N) 中运行,但会占用更多的堆栈空间,并且会访问一个节点两次,一次遍历,一次弹出。

    open class BinaryTree(value: Int) {
    var value = value
    var left: BinaryTree? = null
    var right: BinaryTree? = null
    var consumed: Boolean = false
}

fun branchSums(root: BinaryTree): List<Int> {
    var sumList = ArrayList<Int>()
    var nodeStack = ArrayList<BinaryTree>()
    var valueStack = ArrayList<Int>()

    nodeStack.add(root)

    while(!nodeStack.isEmpty()) {
        val node = nodeStack.get(nodeStack.size-1)

        if (node.consumed) {
            valueStack.removeAt(valueStack.size - 1)
            nodeStack.removeAt(nodeStack.size - 1)
            continue
        }

        valueStack.add(node.value)

        if (node.right == null && node.left == null) {
            var sum = 0
            for (value in valueStack) {
                sum += value
            }
            sumList.add(sum)
        }

        if (node.right != null) {
            nodeStack.add(node.right!!)
        }
        if (node.left != null) {
            nodeStack.add(node.left!!)
        }

        node.consumed = true
    }

    return sumList
}

【讨论】:

    【解决方案3】:

    你可以有这个方法:

     public static int getBranchSum(Node root){
        Queue<Node> q = new LinkedList<>();
        q.add(root);
        int sum=0;
        while (!q.isEmpty()) {            
            Node curNode = q.poll();
            sum+=curNode.data;
            if(curNode.left==null || curNode.right==null)
                curNode.visited=true;
            if(curNode.left != null && curNode.left.visited)
                curNode.visited=true;
            if(curNode.left!=null && !curNode.left.visited)
                q.add(curNode.left);
            else if(curNode.right!=null && !curNode.right.visited)
                q.add(curNode.right);
        }
        root.visited=false;
        return sum;
    }
    

    只要输出不等于根数据,就在下面的while循环中调用它。

        boolean flag=true;
        List<Integer> list = new ArrayList<>();
        while(flag){
            int result =getBranchSum(root);
            if(result == root.data)
                flag=false;
            else
                list.add(result);
        }
        System.out.println(list);
    

    然而,只有当我们在节点中有一个访问过的布尔值时,上述方法才有效:

    class Node{
    Node left,right;
    int data;
    boolean visited = false;
    Node(int data){
        this.data=data;
        left=right=null;
    }
    

    【讨论】:

      【解决方案4】:

      没有递归的分支和

      def branchSums(root):
          cs=0
          stack=[{"node":root,"cs":cs}]
          sums=[]
          while(len(stack)>0):
              node_info=stack.pop()
              node,cs=node_info["node"],node_info["cs"]
              if node is None:
                  continue
              cs=cs+node.value
              if node.left is None and node.right is None:
                  sums.append(cs)
                  print(sums)
              stack.append({"node":node.right,"cs":cs})
              stack.append({"node":node.left,"cs":cs})
      
          return sums
      

      【讨论】:

        猜你喜欢
        • 2016-07-20
        • 2016-04-19
        • 2014-03-29
        • 1970-01-01
        • 2014-12-17
        • 2020-08-04
        • 2010-12-07
        • 2020-09-15
        • 1970-01-01
        相关资源
        最近更新 更多