二叉树遍历

本文详细介绍了二叉树的四种遍历方法:递归的前序、中序、后序遍历以及层序遍历。通过递归和非递归方式展示了遍历的过程,并探讨了它们的实现思路和效率差异,帮助读者深入理解二叉树的操作和思维方式。
摘要由CSDN通过智能技术生成

三种递归遍历

在这里插入图片描述如图为一个简单的二叉树:

前序

在这里插入图片描述它的遍历顺序大致如上图,因为他其实每一步都在重复先打印当前节点,在遍历他的左孩子节点,最后遍历右孩子节点,所以完全可以用帝归来实现,中序后序根本上和前序一样,只是顺序不同而已

前序遍历结果为:
在这里插入图片描述

public static void preorder(TreeNode root){
        if (root==null)
            return;
        System.out.printf("%c ",root.val);
        preorder(root.left);
        preorder(root.right);
    }

中序

中序遍历结果为:
在这里插入图片描述

public static void inorder(TreeNode root){
        if (root==null)
            return;
        inorder(root.left);
        System.out.printf("%c ",root.val);
        inorder(root.right);
    }

后序

后序遍历结果为:
在这里插入图片描述

public static void postorder(TreeNode root){
        if (root==null)
            return;
        postorder(root.left);
        postorder(root.right);
        System.out.printf("%c ",root.val);
    }

层序遍历(队列)

相对比于递归遍历和非递归遍历,层序遍历就比较简单好想了,就是按照二叉树的层级第一层,第二层一直到最后一层,将节点依次打印。由于考虑 节点顺序和层序,所以需要借助队列,大致思想为:
1、首先将二叉树的根节点push到队列中,判断队列不为NULL,就输出队头的元素,
2、判断节点如果有孩子,就将孩子push到队列中,
3、遍历过的节点出队列,
4、循环以上操作,直到Tree == NULL。

    public static void levelOrder(TreeNode root) {
        if (root == null)
            return ;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.remove();
            System.out.printf("%c ",node.val);
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
    }

结果如下:
在这里插入图片描述

三种非递归遍历

非递归遍历肯定是需要用到栈的,前序和中序相比较后序会简单一点,但共同之处是都会用到回溯的思想

前序

原理上来说,就是先将父节点入栈且打印,在判断是否存在左节点,存在则继续上述过程,不存在则回溯到上一步的父节点,判断它的右节点是否存在,存在则继续上述过程,不存在再次回溯,直到栈空。

public static void preorder(TreeNode root) {
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();

        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                System.out.printf("%c ",cur.val);
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode pop = stack.pop();
            cur = pop.right;
        }
    }

中序

先将父节点入栈但不打印,判断左节点是否存在,存在则继续上述过程,不存在则回溯并打印当前节点,继续判断右节点是否存在,存在则继续 上述过程,不存在回溯到上一步,直到栈空。

    public static void inorder(TreeNode root) {
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode pop = stack.pop();
            System.out.printf("%c ",cur.val);
            cur = pop.right;
        }
    }

后序

后序遍历整体与前中序遍历过程相似,相比较而言麻烦的问题是对于父节点的打印,需要在其右子树遍历完成的前提下进行。所以不能像前中序遍历一样,在遍历完左子树后,就直接出栈。我们需要利用这个未出栈的栈顶元素去获取右子树,在遍历完右子树后,就可以出栈,并对此节点进行打印,所以我们需要添加一个标记做判断以区分是从左子树取栈还是从右子树出栈。

public static void postorder(TreeNode root) {
        TreeNode cur = root;
        TreeNode last = null;   // 记录上次刚刚后序遍历过的结点
        Stack<TreeNode> stack = new Stack<>();
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode pop = stack.peek();
            if (pop.right == null) {
                stack.pop();
                System.out.printf("%c ",pop.val);
                last = pop;
            } else if (pop.right == last) {
                stack.pop();
                System.out.printf("%c ",pop.val);
                last = pop;
            } else {
                cur = pop.right;
            }
        }
    }

总结

二叉树的几种遍历代表了不同的思考问题的思路(递归,栈,队列),各有优劣,递归简便但执行效率低(重复调用太频繁,浪费空间和时间),非递归较递归而言略复杂不是很好思考,效率较高,而且更重要的是在这个过程中,我们更多地掌握了新的存储形式,以便以后拓宽更多的思考问题的思路。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值