Java 二叉树的无序遍历有什么问题?

Java 二叉树的无序遍历有什么问题?,java,data-structures,binary-tree,inorder,Java,Data Structures,Binary Tree,Inorder,我使用java实现了BinaryTree,并尝试实现有序遍历。我在副本上干运行代码,在这种情况下它工作得很好,但是当我在IDE上运行它时,我得到了无限循环。但是为什么呢? 请帮忙 class BinaryTree{ class Node{ private int data; private Node left, right; public Node(int data) {

我使用java实现了BinaryTree,并尝试实现有序遍历。我在副本上干运行代码,在这种情况下它工作得很好,但是当我在IDE上运行它时,我得到了无限循环。但是为什么呢? 请帮忙

 class BinaryTree{
    
    class Node{
    
            private int data;
            private Node left, right;
            public Node(int data)
            {
                this.data = data;
                left=null;
                right=null;}
}
    public void inOrderTraversal(Node root)
            {
                Stack<Node> stack = new Stack<>();
                Node temp = root;
                stack.push(root);
                while(!stack.isEmpty())
                {
                    temp = stack.peek();
                    if(temp.left!=null)
                    {
                        stack.push(temp.left);
                    }
                    else
                    {
                        temp = stack.pop();
                        System.out.print(temp.data+" ");
                        if(temp.right!=null)
                        {
                            stack.push(temp.right);
                        }
                    }
                }
            }
    
    public static void main(String[] args) {
    
            Node one = new Node(1);
            Node two = new Node (2);
            Node three = new Node(3);
            Node four = new Node(4);
            Node five = new Node(5);
            Node six = new Node(6);
            one.left = two;
            one.right = three;
            two.left = four;
            two.right = five;
            three.left = six
    
            BinaryTrees bn = new BinaryTrees();
            bn.inOrderTraversal(one);
        }
}
类二进制树{
类节点{
私有int数据;
私有节点左、右;
公共节点(int数据)
{
这个数据=数据;
左=空;
right=null;}
}
OrderTraversal中的公共void(节点根)
{
堆栈=新堆栈();
节点温度=根;
栈.推(根);
而(!stack.isEmpty())
{
temp=stack.peek();
如果(左侧温度!=null)
{
堆栈推送(左侧温度);
}
其他的
{
temp=stack.pop();
系统输出打印(温度数据+“”);
如果(临时正确!=null)
{
堆栈推送(右侧温度);
}
}
}
}
公共静态void main(字符串[]args){
节点1=新节点(1);
节点二=新节点(2);
节点三=新节点(3);
节点4=新节点(4);
节点5=新节点(5);
节点6=新节点(6);
一左=二;
一。右=三;
2.左=四;
二。右=五;
3.左=六
BinaryTrees bn=新的BinaryTrees();
bn.有序旅行(一);
}
}

您的代码以
节点根开始
等于
one
左侧为
two
two
左侧为
four
。在执行
else
条件之前,遍历将
two
然后
four
推送到堆栈中。然后你弹出
四个
四个
,由于
四个
在右边没有任何内容,你的
循环重新开始。但是堆栈的顶部现在是两个。在
two
的左边仍然是
four
,因此您将
four
推到堆栈上,从而开始无限循环

您需要一种方法来指示已经访问过的节点。如果确实必须使用堆栈,则应向节点类添加一个新属性,如
private
,并将其初始化为
false
。在每次
temp=stack.pop()
之后,您需要设置
temp.visted=True
,并且只推送到尚未访问的堆栈节点上。例如:

class Node {
    private int data;
    private Node left, right;
    private boolean visited;
    public Node(int data) {
        this.data = data;
        left = null;
        right = null;
        visited = false;
    }
}

public void inOrderTraversal(Node root) {
    Stack<Node> stack = new Stack<>();
    Node temp = root;
    stack.push(root);
    while(!stack.isEmpty()) {
        temp = stack.peek();
        if(temp.left != null && !temp.left.visited) {
            stack.push(temp.left);
        } 
        else {
            temp = stack.pop();
            temp.visited = true;
            System.out.print(temp.data + " ");
            
            if(temp.right != null && !temp.right.visited) {
                stack.push(temp.right);
            }
        }
    }
}

为了解决上述问题,我们可以在这里使用队列和堆栈进行实现

public void inOrderTraversal(Node root) {
        Stack<Node> stack = new Stack<>();
        Queue<Node> out = new LinkedList<>();
        Node temp = root;
        stack.push(root);
        while (!stack.isEmpty()) {
            temp = stack.peek();
            if (temp.left != null && !temp.left.visited) {
                stack.push(temp.left);
            } else {
                temp = stack.pop();
                temp.visited = true;
                out.offer(temp);

                if (temp.right != null && !temp.right.visited) {
                    stack.push(temp.right);
                }
            }
        }
        while(!out.isEmpty())
        {
            Node tempo = out.poll();
            System.out.print(tempo.data+" ");
            tempo.visited=false;
        }
    }
orderTraversal中的公共void(节点根){
堆栈=新堆栈();
Queue out=new LinkedList();
节点温度=根;
栈.推(根);
而(!stack.isEmpty()){
temp=stack.peek();
if(temp.left!=null&!temp.left.visitored){
堆栈推送(左侧温度);
}否则{
temp=stack.pop();
访问温度=真;
报价(临时);
if(临时权限!=null&!临时权限已访问){
堆栈推送(右侧温度);
}
}
}
而(!out.isEmpty())
{
节点速度=out.poll();
系统输出打印(节拍数据+“”);
节拍=假;
}
}

这是正确的解决方案。

什么是
节点
?调用函数时,
Node root
的值是多少?这里的Node是我定义树的左、右指针的内部类,数据和root是树的根(第一个节点)。请在您的问题中提供
Node
的定义,因为它是高度相关的。此外,如果调用函数时节点根恰好指向自身,那么它将递归地继续将自身推到堆栈上,代码将永远循环。太棒了!我会查看您的代码并返回给您。您有机会查看我的答案吗?或者在推堆栈时,检查
temp==temp.left
temp==temp.left
仅当它们是同一个对象时有效。在本例中,OP提供的这种条件无法解析无限循环。适当的解决方法是使用递归。@h0r53先生,我的PostOrderTraversal也有同样的问题。如果我在一次遍历中标记访问的每个节点,那么在其他遍历中它们将不会被打印。你能给我一个具体的解决办法吗。但是,如果我只在程序中使用顺序,那么这个解决方案是有效的。注意在这里使用“正确”这个词。最理想的解决方案是使用递归。通过简单地将print语句上下移动一行,可以修改我提供的递归示例,以实现pre、post和顺序遍历。
public void inOrderTraversal(Node root) {
        Stack<Node> stack = new Stack<>();
        Queue<Node> out = new LinkedList<>();
        Node temp = root;
        stack.push(root);
        while (!stack.isEmpty()) {
            temp = stack.peek();
            if (temp.left != null && !temp.left.visited) {
                stack.push(temp.left);
            } else {
                temp = stack.pop();
                temp.visited = true;
                out.offer(temp);

                if (temp.right != null && !temp.right.visited) {
                    stack.push(temp.right);
                }
            }
        }
        while(!out.isEmpty())
        {
            Node tempo = out.poll();
            System.out.print(tempo.data+" ");
            tempo.visited=false;
        }
    }