为什么我的代码用于计算树的结?

时间:2017-01-19 17:13:29

标签: java recursion tree tree-traversal

我面对经典的“它有效,但我不知道为什么!” - 问题。我只是应用了一个我从另一个有整数的练习中知道的原则,但在这里我必须使用树木。该方法的测试是成功的。我应该计算一棵树的结,我这样做遍历它(在这种情况下: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());

}

2 个答案:

答案 0 :(得分:1)

你并没有真正在树上走来走去,你只能走下去,每次访问每个节点,然后通过让你的树变得越来越简单来做到这一点。

考虑以下树

  a
 / \
b   c
   / \
  d   e

所以你从根开始并检查它是否为空它不是,所以你返回1 + numberKnots(左)+ numberKnots(右)的结果。左边和右边也是树木,它们比

更简单
left  right
  b    c
      / \
     d   e

所以现在你检查b树,它是空的,所以它只返回0.然后你检查c树,它不是空的,所以你返回1 + countKnots(左(c))+ countKnots(右(的) 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

答案 1 :(得分:0)

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

希望有所帮助