【问题标题】:Why does my code for counting the knots of a tree work?为什么我的计算树结的代码有效?
【发布时间】:2017-06-04 12:08:52
【问题描述】:

我正面临着经典的“它有效,但我不知道为什么!” - 问题。我只是应用了一个我从另一个整数练习中知道的原理,但在这里我必须使用树。该方法测试成功。我应该计算一棵树的结,并且我这样做是遍历它(在这种情况下:inorder),每次我成功遍历(意思是:不面对一个空的子树),我都算作结。在这种情况下,我想知道为什么这段代码没有计算太多的结。例如,当我总是向左走并面对一棵空的子树时,我会不会一直向上走,直到我到达一个可以向右走的结?为什么我的代码会避免这种问题?

public static int numberKnots (Tree b) {

  int count = 0;

  if (b.empty()) {
    return 0;
  }

  else {

  traverse.inorder(b.left());
  traverse.inorder(b.right());
  count = 1;
  }

  return count + numberKnots(b.left()) + numberKnots(b.right());

}

【问题讨论】:

    标签: java recursion tree tree-traversal


    【解决方案1】:

    你并没有真正在树上上下移动,你只是向下移动并访问每个节点一次,你通过让你的树越来越简单来做到这一点。

    考虑以下树

      a
     / \
    b   c
       / \
      d   e
    

    所以你从根开始检查它是​​否为空,所以你返回 1 + numberKnots(left) + numberKnots(right) 的结果。 left 和 right 也是树,比 a 简单

    left  right
      b    c
          / \
         d   e
    

    所以现在你检查 b 树,它是空的,所以它只返回 0。然后你检查 c 树,它不是空的,所以你返回 1 + countKnots(left (of c)) + countKnots(right (of c)) 等等。

    计算的每一步都是:

    countKnots(a) 
     = 1 + countKnots(b) + countKnots(c) 
     = 1 + 0 + countKnots(c) 
     = 1 + 0 + 1 + countKnots(d) + countKnots(e) 
     = 1 + 0 + 1 + 0 + countKnots(e) 
     = 1 + 0 + 1 + 0 + 0
     = 2
    

    您的代码可以简化为

    public static int numberKnots (Tree b) {
      if (b.empty()) {
        return 0;
      } else {
        return 1 + numberKnots(b.left()) + numberKnots(b.right());
      }
    }
    

    但是,它似乎不处理不包含左右节点的树节点,所以下面的树会导致错误

    a
     \
      c
    

    【讨论】:

    • 你为什么把b算作空的?在我看来,这也是一个结,因此,它应该给出 1,而不是 0。
    • 对我来说,结只是树的一个入口。你是上面的树应该给出 5。
    • @Julian 从问题中的代码中,如果节点为“空”,则不计算节点,否则检查左右,所以我认为如果节点没有左边,则节点为空或对。我认为这不会改变遍历树的整体工作方式。
    【解决方案2】:

    由于您使用递归,它不会两次遍历同一个节点。所以您的代码工作得很好。考虑 (A) 有两个子节点 (B)&(C) 进一步 (B) 有两个子节点 (B1) &(B2).当通过递归进行遍历时,它使用堆栈。“(将s视为我们的堆栈)”。首先控制到达节点(A),因为它有左孩子(A)被推入堆栈,控制被转移到(B)现在控制被转移到(B)的左孩子(B1)和(B)被推进入堆栈,因为 (B1) 没有任何子节点,它被计算在内并且控制权被转移到堆栈顶部,即 (B) 和 (B) 被计算在内,现在控制权被转移到 (B) 的右子节点 (B2) 和(B2) 被计数并将控制权转移到 (B)。现在 (B) 没有任何代码部分,因此它从堆栈中弹出并且控制权被转移到 (A) 并且 (A) 被计数并且控制权被转移到它的右子节点 (c)。同样地,所有节点都被计算在内而不重复。

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多