Java 如何在二叉树中使用递归进行回溯

Java 如何在二叉树中使用递归进行回溯,java,recursion,binary-tree,Java,Recursion,Binary Tree,我正在尝试插入一个二进制节点。我的代码很复杂,没有希望挽救它,所以我计划重写它(基本上我没有考虑回溯,也没有仔细考虑算法) 我试图使用顺序遍历插入一个二进制节点,但我不明白应该如何回溯 D / \ B E / \ / \ A C F 如何搜索根D的左子树,然后返回并搜索右子树?这可能是一个愚蠢的问题,但我被难倒了。我能想到的最好的办法是: if (!root.hasLeftChild) { root = root.getLeftChild(

我正在尝试插入一个二进制节点。我的代码很复杂,没有希望挽救它,所以我计划重写它(基本上我没有考虑回溯,也没有仔细考虑算法)

我试图使用顺序遍历插入一个二进制节点,但我不明白应该如何回溯

     D
    / \
   B   E 
  / \ / \
 A  C F 
如何搜索根D的左子树,然后返回并搜索右子树?这可能是一个愚蠢的问题,但我被难倒了。我能想到的最好的办法是:

 if (!root.hasLeftChild) {
      root = root.getLeftChild(); 
      recurse(root); 
 } 
但是当我到达底部时,我不能带着根再往上爬。此外,它也不能解决这样的问题:如果我到达左下角的节点,我必须在开始回溯之前填充该节点的两个子节点

     D
    / \
   B   E 
  / \ / \
 A  C F 

我想我是想错了

试试这个例子。它使用递归按顺序访问所有节点:

public class Example {

    public static void main(String[] args) {
        visitInOrder(new Node("D",
            new Node("B", new Node("A"), new Node("C")),
            new Node("F", new Node("E"))));
    }

    public static void visitInOrder(Node node) {
        if (node != null) {
            visitInOrder(node.left());
            System.out.println(node.name());
            visitInOrder(node.right());
        }
    }
}

class Node {

    private final String name;
    private Node left;
    private Node right;

    public Node(String name) {
        this(name, null);
    }

    public Node(String name, Node left) {
        this(name, left, null);
    }

    public Node(String name, Node left, Node right) {
        this.name = name;
        this.left = left;
        this.right = right;
    }

    public String name() { return name; }    

    public Node left() { return left; }

    public Node right() { return right; }
}
输出:

A
B
C
D
E
F
树:

     D
    / \
   B   E 
  / \ / \
 A  C F 
对于递归:

使用有序遍历

  if (root == null) 
    return;

      recurse(root.getLeftChild()); 
      int rootData = root.getData();
      recurse(root.getRightChild()); 
现在,它是如何重现的:

root.getLeftChild()
将继续递归调用左子级,除非它命中
null
节点(因此控件不会转到
recurse(root.getRightChild());
除非命中
null
节点)

树走了这么远:

         D
        / 
       B    
      / 
     A  
    /
  null <-- current Position
然后,它进入下一个递归调用,
recurse(root.getRightChild())

步骤:

  • A
    调用其左侧的
    B
    ,因此A被推入堆栈
  • B
    调用其左边的
    C
    ,因此B被推入堆栈
  • C
    调用其左边的
    null
    ,所以C被推入堆栈
  • 现在C的
    都是
    null
    …因此这标志着这个节点递归的结束,因此它的
    pop
    从堆栈中退出
  • 现在,C被完全遍历,所以,当B称为C时,控制返回到B并检查哪一行调用了这个命令
  • 当执行
    b.left
    时,它现在将转到
    b.right
    push
    D。。。。。。这就是所谓的递归堆栈

    • 所以你正在尝试进行深度优先搜索——你可以在任何数量的书籍或维基百科上找到

      从本质上讲,它们的关键在于,您的函数对每个子函数递归地调用自己。e、 g:

      public Node findSpot(Node node, List<Node> visits){
          visits.add(node);
          //condition check, return this node if its the right node.
          Node result = null;
          for(Node child : node.getListChildren()){
              if((result findSpot(child)) != null){
                   return result
              }
          }
          return null;
      }
      
      公共节点findSpot(节点、列表访问){
      添加(节点);
      //条件检查,如果是正确的节点,则返回此节点。
      节点结果=null;
      对于(节点子节点:Node.getListChildren()){
      如果((结果findSpot(子项))!=null){
      返回结果
      }
      }
      返回null;
      }
      

      因此,这将递归地检查节点,为树中的每一层深度在堆栈上放置一个新方法。然后它检查下一个分支,如果它没有找到它要找的东西。访问列表将让您看到它访问节点的顺序,因此您可以查看。这将帮助您了解它是如何工作的。

      您的方法
      visitInOrder
      实际上是在进行预订单访问,但您的结果是预期的订单结果。最好修复这个方法。@seelenVirtuse是的,你是对的。现在我修改了订单,但没能修改输出。我会马上做的。谢谢嗯:你误解我了!输出已经正确。一切正常。只是方法不正确。现在您修复了该方法,但也完全破坏了输出。现在您必须将输出更改回初始形式。但是是:左、自、右。输出正常,但完全混乱。确认的答案已经抓住了解决方案。我认为我的输出是正确的,不是吗?完全正确:左,自,右!对于父节点为“B”、左子节点为“a”、右子节点为“C”的子树(如问题中所述),顺序输出为“ABC”。B作为当前节点-访问时-位于A和C之间!另外,我没有看一看,你的回答是否正确。我只看到,您发布了一个按订单输出,但建议使用预订单方法。目前,您有一个按顺序方法和一个既不按顺序也不按前顺序也不按后顺序的输出。搞砸了。这个例子的顺序输出将是排序后的输出。好吧,我对下一个递归调用是如何进行的有点困惑。当root==null时,该方法返回,那么为什么它会继续?我认为你需要研究递归堆栈…当一个程序被递归调用时,每个被调用的子程序都被操作到一个新的内存
      堆栈中
      …一旦当前堆栈操作完成,控件返回到刚才完成的stackahhh,我以前从未真正使用过递归堆栈,但我的教授在讲座中试图解释它。我看了一段YouTube视频,解释得更清楚了。所以基本上,堆栈看起来像DBA,然后它点击null并弹出A,并从int rootData=root.getData()解析;并递归getRightChild。因为没有什么可以做的了,它返回到B,做同样的事情,然后返回到A,在右边再次运行,然后尝试再次得到leftChild并运行方法实际上,还有一件事。为什么是最后一个?当D通过该方法时,它对两个子对象都为null,所以它不也应该被弹出吗?所以它看起来像:ABD->AB->A->E->EF->E->G?注意
      B
      的递归是如何发生的,
      B->C->null->C弹出->返回到B->D->null->D弹出->返回到B->B弹出
      …发生这种情况是因为,一旦访问了两个孩子,就只弹出了父母。。。。在树上,如果你有任何疑问,只要了解最后一个父项和叶子是如何操作的,那么它将帮助你更好地理解!!:)
           A
          / \
         B   E 
        / \ / \
       C  D F 
      
      public Node findSpot(Node node, List<Node> visits){
          visits.add(node);
          //condition check, return this node if its the right node.
          Node result = null;
          for(Node child : node.getListChildren()){
              if((result findSpot(child)) != null){
                   return result
              }
          }
          return null;
      }