二叉树的前中后序遍历

穿精又带淫゛_ 提交于 2020-01-24 02:21:21

前中后序遍历的递归方式。

前序遍历
中序遍历
后序遍历

其实,前中后序的遍历,走的路径是一样的,只是访问结点的时间不同而已。
共性

非递归进行前中后序遍历(使用栈)

题目描述:
List preorderTraversal(TreeNode root)
List inorderTraversal(TreeNode root)
List postorderTraversal(TreeNode root)
题目链接:
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
https://leetcode-cn.com/problems/binary-tree-postorder-traversal/

1.前序遍历

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();

        //迭代解决 使用栈
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode tmp = root;
        while (!stack.isEmpty() || tmp != null) {
            while (tmp != null) {
            	//前序遍历 第一次路过就访问
                list.add(tmp.val);
                stack.push(tmp);
                tmp = tmp.left;
            }
            tmp = stack.pop();
            tmp = tmp.right;
        }

        return list;
    }

2.中序遍历

 public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        //迭代解决 使用栈
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode tmp = root;
        while (!stack.isEmpty() || tmp != null) {
            while (tmp != null) {
                stack.push(tmp);
                tmp = tmp.left;
            }
            tmp = stack.pop();
            //中序遍历 第二次路过就访问
            list.add(tmp.val);
            tmp = tmp.right;
        }

        return list;
    }

3.后序遍历

后序遍历和前序遍历、中序遍历不太一样。之前使用栈时,前序遍历是在元素入栈时就访问,中序遍历是在元素出栈时再访问。一个元素就入栈、出栈共两次访问,没有再第三次路过,因此后序遍历不容易直接写出来。
但是我们观察到:
后序遍历: 左 右 根 的顺序, 如果我们把它顺序反过来呢? 就是 根 右 左 ,可以认为这是一种特殊的“前序遍历”。我们可以按照前序遍历的思路,很容易的写出 根 右 左 的顺序,然后把结果反过来不就可以了吗!

	public List<Integer> postorderTraversal(TreeNode root){
        //后序遍历
        //左右根  反过来的顺序就是 根右左,根右左是一种特殊的"前序遍历",这样遍历出来之后,只需要把它反过来就行了。
        LinkedList<Integer> result = new LinkedList<>();
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode tmp = root;
        while (tmp != null || !stack.isEmpty()) {
            while (tmp != null) {
                stack.push(tmp);
                //插到第一个,相当于就是进行了逆序
                result.addFirst(tmp.val);
                tmp = tmp.right;
            }
            tmp = stack.pop();
            tmp = tmp.left;
        }
        return result;
    }

还有一种思路:

	/**
     * 后序遍历
     * 后序遍历是第三次遇到该结点时,才可以进行访问。
     * 使用栈来实现。
     * 要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。
     * 当结点没有左右子节点时可以直接访问,或者上一个访问的子节点是自己的儿子结点,则可以访问该结点。并将该结点弹栈
     * 否则就将该结点的右儿子和左儿子入栈。保证出栈时左儿子在前
     * @param root
     * @return
     */
    public List<Integer> postorderTraversal(TreeNode root) {
        //迭代实现
        List<Integer> result = new LinkedList<>();
        if (root == null) {
            return result;
        }
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode cur = null, pre = null;
        stack.push(root);
        while (!stack.isEmpty()) {
            cur = stack.peek();
            if (!hasChild(cur) || lastVisitedIsChild(cur, pre)) {
                //访问
                result.add(cur.val);
                pre = stack.pop();
            } else {
                if (cur.right != null) {
                    stack.push(cur.right);
                }

                if (cur.left != null) {
                    stack.push(cur.left);
                }
            }
        }

        return result;
    }
    
    private boolean lastVisitedIsChild(TreeNode cur, TreeNode pre) {
        return pre != null && (pre == cur.left || pre == cur.right);
    }

    private boolean hasChild(TreeNode t) {
        return (t.left != null) || (t.right != null);
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!