【问题标题】:Tracing through a Binary Tree跟踪二叉树
【发布时间】:2015-08-02 09:55:38
【问题描述】:

我有以下二叉树

    3
   /  \
  5     2
 / \    /
1   4   6

我的周是递归,所以请耐心等待,我需要你的帮助来追踪它以使其正确。

我有以下代码,它的作用是在 Post Order 中打印节点。 所以答案是 1 4 5 6 2 3

void Postorder(Node root) {

if(root == null){
    return;
}

Postorder(root.left);
Postorder(root.right);
System.out.print(root.data + " ");
}

让我们追踪:

Root = 3 (top node), not null, Root.left(5) - 回到函数

Root = 5, Not null, Root.left(1) - 返回函数

Root = 1, Not null, Root.left(null), continue, Root.right(null)

打印 1

现在这就是我感到困惑的地方,Root = 1 在这一点上,我看不出我如何回到 5,然后转到逻辑中的正确节点。另外,当我回到 5 时,我在哪里检查 1 是否被访问过?

我很困惑。

感谢您的帮助。

【问题讨论】:

  • 在调试器中单步调试。
  • 当所有PostOrder(root.left) 调用都返回时,您最多可以返回 5。您检查 1 是否已在 System.out.print(root.data + " ") 中被访问,就像所有其他节点一样。请记住,从节点 1 调用的 PostOrder(root.left)PostOrder(root.right) 将在满足 root == null 条件时立即返回,只留下 System.out.print 为节点 1 执行。

标签: java binary-tree binary-search-tree


【解决方案1】:

是的,所以当您位于 Root 1(叶子)时,它将返回到调用它的节点 (5)。

由于在“Root 5”,它刚刚调用完Postorder(root.left);(刚刚从打印1返回),下一行将运行并调用Postorder(root.right);

这将调用 root = 4。不为空,root.left(null),继续,root.right(null),继续,现在 print 4

现在我们跳回到调用节点,root = 5。现在它已经调用了Root.left(1);Root.right(4);。所以现在它要去print 5

它现在将返回到调用节点 - 在这种情况下是整个树的根,root = 3,现在它将以类似的方式遍历右侧。

【讨论】:

    【解决方案2】:

    Understanding and visualizing recursionMaybye 这会帮助你,因为你理解递归错误。你需要记住所有的函数调用。

    【讨论】:

      【解决方案3】:

      递归很简单。您需要做的就是不断地将Binary Search Tree 分成左右子树。

      您可能还需要考虑为您的变量创建 getters 以更好地封装您的 Node 类。

      后序功能

      public void Postorder( Node root )
      {
          if( root == null )
              return;
      
          // Output the left tree.
          if( root.left != null )
              Postorder( root.left );
      
          // Output the current node.
          System.out.print( root.data + " " );
      
          // Output the right tree.
          if( root.right != null )
              Postorder( root.right );        
      }
      

      【讨论】:

        【解决方案4】:

        也许图片会有所帮助。我发现递归也很困难,而且我发现图片很有用。最好在单独的窗口中打开图表并在旁边提供说明。

        首先,递归使用称为堆栈的东西。这是您在图中看到的一堆四个矩形。例如,最后有两个空栈。假设函数A()A 终止之前调用了函数B()。然后需要发生的是我们在中途执行A(),然后执行B(),然后返回并完成执行A()。但是当我们去执行B()时,我们需要记住我们在A()中的位置。因此,我们需要将有关A()B() 的信息存储在堆栈中的各个矩形中。这样,在我们执行完B() 之后,我们就知道我们在A() 中的中断位置并且可以完成函数。

        因此,如果我们使用堆栈图逐步完成递归,也许会有所帮助。还假设我们有这个:

        public static void main( String[] args ) {
            Postorder(3);
        }
        

        1

        所以最初,主运行及其内容被添加到堆栈的底部,正如我们在第 1 部分中看到的那样。

        1->2

        但是当main() 调用Postorder(3) 时,它还没有终止。因此,在另一个堆栈帧中,我们添加了Postorder(3) 函数调用的内容。您可以在第 2 部分中看到这一点。黄色箭头会记住我们在执行另一个函数之前在每个堆栈帧中停止的位置。

        2->3

        现在,我们正在执行Postorder(3),我们到达了函数调用Postorder(5)。但是Postorder(3)还没有运行完,所以在另一个栈帧中,我们要添加Postorder(5)的内容。您可以在第 3 部分中看到这一点。

        3->4

        现在我们正在执行Postorder(5)。我们到达函数调用Postorder(1)。但是Postorder(5)还没有运行完,所以在另一个stackframe中,我们要添加Postorder(1)的内容。为简单起见,由于 1 没有子节点,我们将说 Postorder(1) 等价于 Print(1)。这对应于第 4 部分。

        4->5

        现在,在第 4 部分,Print(1) 执行,Postorder(1) 终止。当Postorder(1) 终止时,可以将其从堆栈中移除。另外,由于Postorder(1) 完成,我们可以继续执行Postorder(5)。黄色箭头告诉我们,在我们跳下去执行另一个函数之前,我们在Postorder(5) 的第 1 行停止了。好吧,我们现在可以转到Postorder(5) 的第 2 行。这对应于第 5 部分。

        5->6

        Postorder(5) 的第 2 行是命令 Postorder(4)。由于Postorder(5) 还没有执行完毕,我们必须将Postorder(4) 的内容添加到另一个堆栈帧中。这对应于第 6 部分。

        ...

        从那时起,想法几乎相同。如果您仍然希望我逐步完成剩余的 8 个部分,请告诉我。之后会有点乏味。希望这个视觉效果有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-14
          • 1970-01-01
          相关资源
          最近更新 更多