二叉树的遍历

二叉树的遍历

二叉树遍历包括前序遍历、中序遍历、后续遍历和层序遍历

  • 前序遍历:根节点 -> 左子树 -> 右子树
  • 中序遍历:左子树 -> 根节点 -> 右子树
  • 后序遍历:左子树 -> 右子树 -> 根节点
  • 层序遍历:按照二叉树的层级,从上到下,从左到右遍历

前序遍历、中序遍历和后序遍历都有递归和非递归的方法

递归

递归的形式很简单,先序遍历是每次访问到了节点就输出,然后依次递归的遍历左子树和右子树;中序遍历是访问完了左子树,在输出根节点;后序遍历则是访问完了左子树和右子树后再回到根节点输出。三种遍历递归的形式是一致的,只是访问的顺序不一样,代码如下

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

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

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

非递归

在树的遍历过程中,我们都是遵循着一样的遍历路线,但是访问的时机不一样。我们的遍历路线都是顺着左子树深入,当深入左子树到底的时候再深入右子树,只不过先序遍历是每次遍历到节点的时候先访问节点,中序遍历是左子树遍历完了再访问节点,后序遍历是左右子树都遍历完了再访问节点。从中序遍历着手,我们发现遍历的时候依次深入遍历左子树直到停止左子树的遍历,然后输出最后一个遍历的左子树节点,这种结构有点像是栈的后进先出,所以可以考虑使用一个栈来保存数据;那么先序遍历就是入栈之前就访问节点,中序遍历是入栈后再出栈的时候访问节点;后序遍历复杂一点,因为节点出栈后,还要先访问其右子树,之后才能访问该节点,那么可以将节点再次入栈,然后访问其右子树,这样的话,节点就有两次入栈,所以需要额外的变量记录节点是不是第一次入栈。我们可以更改树的结构,新增一个变量来实现。
非递归的代码如下:

    public static void preOrder(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();

        while ( root != null || !stack.isEmpty()) {
            // 左子树压栈直到左子树为空
            while (root != null) {
                // 在入栈前访问
                System.out.print(root.val + " ");
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            // 转向右子树
            root = root.right;
        }
    }

    public static void inOrder(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();

        while ( root != null || !stack.isEmpty()) {
            // 左子树压栈直到左子树为空
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            // 出栈时访问
            System.out.print(root.val + " ");
            // 转向右子树
            root = root.right;
        }
    }

    private static void postOrder(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();

        while (root != null || !stack.isEmpty()) {
           // 左子树压栈直到左子树为空
            while (root != null) {
                stack.push(root);
                root.isFirst = true; // 表明是第一次入栈
                root = root.left;
            }

            root = stack.pop();
            if (root.isFirst) {
                stack.push(root);
                root.isFirst = false;
                root = root.right;
            } else {
                System.out.print(root.val + " ");
                root = null;
            }

        }
    }

还有一种先序遍历和后序遍历的方法
对于先序遍历,我们先把根节点入栈,在出栈的时候访问,然后把根节点的左右子节点入栈,根据栈的特点,这个时候应该先入栈右节点,再入栈左节点,这样出栈的时候就是先访问的左节点,然后把该左节点的右节点和左节点分别入栈,依次进行下去,就能得到先序遍历的结果

    private static void preOrder2(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        if (root != null)
            stack.push(root);

        while (!stack.isEmpty()) {
            TreeNode node = stack.poll();
            System.out.print(node.val + " ");

            if (node.right != null)
                stack.push(node.right);
            if (node.left != null)
                stack.push(node.left);
        }
    }

用同样的方式考虑后序遍历的时候,发现用一个栈没有办法一步到位,发现还需要一个辅助栈来存储出栈的结果。
与上述先序遍历类似,先入栈根节点,然后入栈左节点,在入栈右节点,出栈的时候,将出栈的节点再存入一个新的栈中。

    private static void postOrder2(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        LinkedList<TreeNode> result = new LinkedList<>();
        if (root != null)
            stack.push(root);

        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            result.push(node); // 出栈的结果存入新的栈中

            if (node.left != null)
                stack.push(node.left);
            if (node.right != null)
                stack.push(node.right);
        }

        for (TreeNode node : result) {
            System.out.print(node.val + " ");
        }
    }

层序遍历

层序遍历可以用一个队列来辅助,比较简单,具体如下:

    private static void levelOrder(TreeNode root) {
        LinkedList<TreeNode> queue = new LinkedList<>();
        if (root != null)
            queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            System.out.print(node.val + " ");
            if (node.left != null)
                queue.offer(node.left);
            if (node.right != null)
                queue.offer(node.right);
        }
    }

层序遍历和上述的先序遍历和后序遍历的方法时候有相似性的,只不过前者是用队列后者是用栈来实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值