Java实现二叉树的遍历,递归与非递归 附带解释

Java实现二叉树,三种遍历的递归和非递归方法实现以及解释

直接上代码,树的结构:

class TreeNode{
    int val;
    TreeNode left;
    TreeNode right;
    public TreeNode(int val){
        this.val = val;
    }
}

先序遍历(递归)

public static void preOrder(TreeNode root){
        if(root==null) return;
        System.out.print(root.val+" ");
        preOrder(root.left);
        preOrder(root.right);
    }

中序遍历(递归)

public  static void inOrder(TreeNode root){
        if(root==null) return;
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }

后序遍历(递归)

public  static void postOrder(TreeNode root){
        if(root==null) return;
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val+" ");
    }

可以看到递归的思路非常的直接,不必过多讲解。下面着重看一看非递归的写法:

前序遍历(非递归)

public static void preOrder2(TreeNode root){
        Stack<TreeNode> s = new Stack<>();
        while(root!=null || !s.isEmpty()){
            while(root!=null){
                System.out.print(root.val+" ");
                s.push(root);
                root = root.left;
            }
            if(!s.isEmpty()){
                root=s.pop();
                root=root.right;
            }
        }
    }

不使用递归时,我们需要一个栈来存储我们遍历的路径。由于前序遍历的顺序是中左右,所以每到一个根节点我们先获取它的值,然后找左子节点,然后再右。所以先遍历到最左,然后再遍历最左的父节点的右子树,这个回溯的过程通过一个栈来实现,每遍历完一个节点的所有子树就将这个节点从栈中弹出。

中序遍历(非递归)

public  static void inOrder2(TreeNode root){
        Stack<TreeNode> s = new Stack<>();
        while(root!=null || !s.isEmpty()){
            while(root!=null){
                s.push(root);
                root = root.left;
            }
            if(!s.isEmpty()){
                root = s.pop();
                System.out.print(root.val+" ");
                root = root.right;
            }
        }
    }

中序遍历和先序遍历思路相同,只是改变一下读取数据的时机,在遍历完左边再读取数据。

后序遍历(非递归)

public  static void postOrder2(TreeNode root){
        Stack<TreeNode> s1 = new Stack<>();
        Stack<TreeNode> s2 = new Stack<>();
        s1.push(root);
        while(!s1.isEmpty()){
            root = s1.pop();
            s2.push(root);
            if(root.left!=null){
                s1.push(root.left);
            }
            if(root.right!=null){
                s1.push(root.right);
            }
        }
        while(!s2.isEmpty()){
            System.out.print(s2.pop().val+" ");
        }
    }

后续遍历和前面的思路不同,由于后续遍历需要最后遍历根节点,所以需要另一个数据结构来保存我们需要输出的路径,我们选择再使用一个栈。
一共使用两个栈,s2用来保存后续序列,s1用来遍历二叉树。
我们希望得到的结果是左右中,但是因为栈的特性,s2入栈的顺序应该是中右左。首先我们把s1走到的节点加入s2作为中,然后如果s1这个节点有左子节点,先将左子节点加入s1,如果有右子节点,再将右子节点加入s1。你可能要问不是说好的中右左,为什么这里又是先左后右呢?因为s1也是一个栈,从s1中pop() 的时候顺序还要反过来,所以先加左,在加右。
最后,s2中已经保存好了我们需要的后序序列的逆序,只需要循环出栈遍历即可。

运行测试类以及结果:

测试类:

public static void main(String[] args) {
        TreeNode root = new TreeNode(0);
        root.left = new TreeNode(1);
        root.right = new TreeNode(2);
        root.left.left = new TreeNode(3);
        root.left.right = new TreeNode(4);
        root.right.left = new TreeNode(5);
        root.right.right = new TreeNode(6);
        BinaryTree bTree = new BinaryTree();
        System.out.println("Recursive-----------|");
        bTree.preOrder(root);
        System.out.println();
        bTree.inOrder(root);
        System.out.println();
        bTree.postOrder(root);
        System.out.println();
        System.out.println("Non-Recursive-------|");
        bTree.preOrder2(root);
        System.out.println();
        bTree.inOrder2(root);
        System.out.println();
        bTree.postOrder2(root);
    }
}

结果:

Recursive-----------|
0 1 3 4 2 5 6 
3 1 4 0 5 2 6 
3 4 1 5 6 2 0 
Non-Recursive-------|
0 1 3 4 2 5 6 
3 1 4 0 5 2 6 
3 4 1 5 6 2 0 
Process finished with exit code 0
发布了11 篇原创文章 · 获赞 0 · 访问量 3042

猜你喜欢

转载自blog.csdn.net/weixin_40407203/article/details/105502417
今日推荐