【问题标题】:Why is this preorder traversal returning the last nodes?为什么这个前序遍历会返回最后一个节点?
【发布时间】:2019-11-17 19:30:15
【问题描述】:

我明白为什么字母 [A, B, D] 会附加到列表中。但我不明白最后两个字母 [E, C] 是如何添加的。 在 pre_order('C', nodes) 之后,字母 'C' 没有左孩子,函数怎么知道要上一级字母 'B' 并检查它的孩子,等等?看树图: Tree

def pre_order(root, nodes):
    nodes.append(root.data)
    if root and root.left:
        pre_order(root.left, nodes)
    if root and root.right:
        pre_order(root.right, nodes)
    return nodes

    print(pre_order(root, [])) #prints ['A', 'B', 'D', 'E', 'C']

【问题讨论】:

  • Google 循环和预购。当某些东西没有子节点或子节点已被检查时,函数返回并且执行它的任何函数都会继续。
  • @h4z3,它不会继续执行任何执行它的函数。在字母“D”之后,它调用带有字母“E”的函数。为什么?
  • 是的,它确实会继续——但执行它的是同一个函数(具有不同的参数)。这就是递归(抱歉我之前的错误,我是音译而不是翻译)。
  • @GoldenRetriever 这就是您在预订中遍历树的方式。

标签: python recursion linked-list binary-tree preorder


【解决方案1】:

执行后,函数返回到调用它的任何地方,在这种情况下 - 调用相同的函数但具有不同的参数。

让我们看看它在您的示例中是如何工作的。每个缩进都是一个新的执行 - 看看我们如何返回到前一个缩进并继续。

  • 我们从节点 A 上的 pre_order 开始,列表为空
    • 将 A 附加到当前列表,新列表 = [A]
    • 第一个 if 命中,所以我们在 B 上执行列表:
      • 将 B 附加到当前列表 [A],新列表 = [A, B]
      • 第一个 if 命中,所以我们在 D 上执行列表:
        • 将 D 附加到当前列表 [A, B],新列表 = [A, B, D]
        • 第一个 if 没有命中,因为 D 没有左孩子
        • 第二个if 没有命中,因为 D 没有正确的孩子
        • 返回 [A, B, D]
      • 我们得到了内部执行的结果,并从它开始的地方继续(在 B 中)
      • 第二个 if 命中,所以我们在 E 上执行列表(由于可变性,现在在内部函数中进行了更改)
        • 将 E 附加到当前列表 [A, B, D],新列表 = [A, B, D, E]
        • 第一个 if 没有命中,因为 E 没有左孩子
        • 第二个if 没有命中,因为 E 没有正确的孩子
        • 返回 [A, B, D, E]
      • 我们得到了内部执行的结果,并从它开始的地方继续(在 B 中)
      • 返回 [A, B, D, E]
    • 我们得到了内部执行的结果,并从它开始的地方继续(在 A 中)
    • 第二个if 命中,所以我们在 C 上执行列表(现在在内部执行中多次更改)
      • 将 C 附加到当前列表 [A, B, D, E],新列表 = [A, B, D, E, C]
      • 第一个 if 没有命中,因为 C 没有左孩子
      • 第二个if 没有命中,因为 C 没有正确的孩子
      • 返回 [A, B, D, E, C]
    • 我们得到了内部执行的结果,并从它开始的地方继续(在 A 中)
    • 返回 [A, B, D, E, C]
  • 我们回到第一次执行 pre_order 的地方 - 即打印函数

[列表中可能有轻微的拼写错误和小错误,我复制粘贴了大部分内容,可能我忘记更改某些内容]

【讨论】:

  • 感谢您提供非常详细的描述。但是,当使用与最初调用它的相同参数调用该函数时,它为什么没有在无限循环中运行?因为,假设它再次被 B 调用,是什么阻止它再次访问 B 的左孩子?
  • 它返回到调用,而不是函数的开头。基本上,您实际上是在同一行(如果您给它们编号,那么更容易想象)但在执行之后。就像x = len(range(10)) + 1 将首先进入range(10) 并创建它并返回它被调用的位置,然后len 执行并返回它被调用的位置,然后+ 执行并返回,然后x 被分配。 10+1 不关心它是如何得到 10 (len),也不关心它的结果会发生什么 (x=)。
  • 存储先前的状态,以便程序知道它需要继续的地方。它存储在一个特殊的堆栈上,“堆栈溢出”是一个异常,当您收到太多调用(例如,太长或无限递归)并且您没有地方存储以前的状态时会引发异常。
猜你喜欢
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-14
相关资源
最近更新 更多