java version "1.8.0_92"
我正在研究树以及如何使用递归遍历它们。但我对此感到困惑。
public void preOrder(BinaryTree root) {
if(root != null) {
System.out.println(root);
preOrder(root.leftChild); <-- this gets called and will start from the top of the function
preOrder(root.rightChild); <-- how can this get called if the top one will always calls itself?
}
}
我认为第二个preOrder将永远不会被调用,因为上面的调用将始终调用自身,因此第二个将永远不会被执行。
答案 0 :(得分:1)
总是自己调用。它继续前进,直到它以null leftChild结束。然后执行返回而不做任何事情 - 它备份一个级别并在最低级别父节点的rightChild上重复。当该调用也耗尽了子节点时,执行从处理这个最低级别的父节点返回,再次备份一个调用,并执行的
答案 1 :(得分:1)
一旦root.leftChild
变为空(即,当你到达树的叶子时),preOrder
将被调用如下:preOrder(null)
。发生这种情况时,条件将评估为false
,并且递归退出并停止,此时将评估preOrder(root.rightChild)
。
这是一个呼叫追踪(在Scala中):
case class BinaryTree(nodeName: String, leftChild: Option[BinaryTree], rightChild: Option[BinaryTree]) {
def preOrder(root: Option[BinaryTree], depth: Int = 0) {
root match {
case Some(root) => {
println(" " * depth + root.nodeName)
preOrder(root.leftChild, depth+4)
preOrder(root.rightChild, depth+4)
}
case None => println(" " * depth + "leaf")
}
}
}
val tree = new BinaryTree(
"root",
Some(new BinaryTree(
"a",
Some(new BinaryTree("aa", None, None)),
Some(new BinaryTree("ab", None, None)))),
Some(new BinaryTree(
"b",
Some(new BinaryTree("ba", None, None)),
Some(new BinaryTree("bb", None, None)))))
tree.preOrder(Some(tree))
root
a
aa
leaf
leaf
ab
leaf
leaf
b
ba
leaf
leaf
bb
leaf
leaf
答案 2 :(得分:1)
想想它已经打开了一大堆门,直到找到你要找的东西,然后你必须回去关闭/检查其他的。
public void preOrder(BinaryTree root) {
if(root != null) {
System.out.println(root);
preOrder(root.leftChild); <-- this gets called and will start from the top of the function
preOrder(root.rightChild); <-- how can this get called if the top one will always calls itself?
}
}
我们可以使用匹配代码替换preOrder调用,如下所示:
public void preOrder(BinaryTree root) {
if(root != null) { <-- note the if check
System.out.println(root);
if(root.leftChild!= null) { <-- note the if check
System.out.println(root.leftChild.leftChild);
preOrder(root.leftChild.leftChild); <- this expands into another if block
preOrder(root.leftChild.rightChild); <- this also expands
}
if(root.rightChild!= null) { <-- note the if check
System.out.println(root.rightChild.leftChild);
preOrder(root.rightChild.leftChild);
preOrder(root.rightChild.rightChild);
}
}
}
它不断向外扩展...直到你遇到特殊的“基数”,如果条件停止递归。在这种情况下,当您找到树的叶节点,即node == null时,它会停止扩展,因为if条件不再为真,并且一切都开始自行崩溃,或者换句话说,它可以继续正常执行代码块。
答案 3 :(得分:1)
当你刚刚开始学习时,递归似乎会被混淆。首先,您可以想到一个子问题。对于preOder,它总是打印出根节点,左侧节点,然后是右侧节点。您所需要的只是解决一个子问题。 (下面一个简单的基本树)
root
/ \
left right
/ \
... ...
现在回过头来看看代码:
if(root != null) {
System.out.println(root);
preOrder(root.leftChild); // the left node now becomes another root, and keep making the next left node root until the next left node is null.
preOrder(root.rightChild); // this line of code won't be executed until the last preOrder function call its root == null(hit the condition.)
}
信任递归;如果您的情况正确,它将始终为您完成其余部分。我同意运行调试模式以便更好地理解。当您尝试理解代码如何工作时,学习如何使用“step in”非常有用。