【蓝桥Java每日一练】————6.二叉树的前中后序遍历(递归与迭代)(上)

简介: 今天给大家带来的每日一题是二叉树的前中后序遍历(其实是三题哈哈哈哈哈),二叉树是非常非常重要的基础结构,其中它的前中后序三种遍历又显得尤为基础和重要。每日一练的目的更多是和大家巩固基础能力,会则巩固之,不会更应学习之。

☀️1.浅聊如何理解递归


        递归这个东西,我相信很多兄弟根本弄不明白,有时候看到别人递归一行代码搞定的题目,自己不仅羡慕,还看不懂(没错这就是我了-。-)。


       首先我们要明确递归的三要素:


        1.确定递归函数的参数和返回值:我们需要确定在递归的过程中哪些参数是需要被处理的,而且我们还需要确定每次递归的返回值是什么,进而取确定递归函数的返回值类型。


        2.确定递归出口(终止条件):很多人在写递归方法时,总是遇到statckoverflow的错误,也就是栈溢出。递归既然是一直往下循环,那必然需要有一个循环出口,这和我们平常写的for和while是同一个道理。如何确定递归出口呢?这就要根据题目的意思去确定了。


       3.确定单层递归的要干啥:我相信这是大家最难处理的地方了,为什么会如此呢?要我来说就是多愁善感,因为许多兄弟太过去关心上一层和下一层干啥,让自己的脑袋也递归起来,最后脑袋栈溢出快疯掉了。所以大家一定要走出这个误区,这层有些什么东西,我们需要干些什么,干完了就不管了,千万不要过多关心其他层的事情。      


       同时在这给大家推荐一篇宝藏文章,也是让我自己真正学会递归三部曲的文章,相信一定会给大家带啦帮助:三道题套路解决递归问题


🍅1.二叉树的前序遍历(中左右)


给你二叉树的根节点 root ,返回它节点值的 前序 遍历。


题目链接:二叉树的前序遍历https://leetcode-cn.com/problems/binary-tree-preorder-traversal/            


🍅1.递归解法


           为什么先要和大家讲递归的解法呢?因为其实迭代解法也是利用的我们的栈statck,而递归本身就是隐式的使用了栈,这个相信大家也知道。而且二叉树的前中后三序遍历中,递归的解法都比迭代要简单的多,很多兄弟肯定说你别忽悠人。为什么呢?因为二叉树遍历的递归解法它的三要素都特别简单,函数返回值为void,参数就一个节点,递归出口也就节点为null,也非常容易,甚至连最难的处理逻辑也就只有一句话,那就是把当前节点的val放入到答案集合中。甚至会发现,前中后序的递归解法代码都差不多长一样,先理解递归再去写迭代会更加帮助我们理解。            


class Solution {
    //用来放答案的集合,设为全局变量
    List<Integer> list=new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
            if(root==null) return list;
            //注意我们一开始传入的节点是根节点
            test(root);
            return list;
    }
    public void test(TreeNode root){
        //递归出口
        if(root==null){
            return;
        }
        //先放入根节点
        list.add(root.val);
        //递归处理左子树
        test(root.left);
        //再处理右子树
        test(root.right);
    }
}

       这里要和兄弟们讲一下可能对于上面代码的疑问,后面的两种递归也是同理,就只讲一遍了。


1. list一定要是全局变量吗?


       这个当然不是,因为list在每层递归都会使用到它,所以我们也可以把他在preorderTraversal方法中实例化后,当作参数每次传递,当然写成全局变量会更加方便。    


2. 为什么要重新写一个test方法来递归?


       因为preorderTraversal方法需要返回一个list集合作为答案,而我们的递归逻辑其实是每次将元素放入到list中,是不需要返回值的,所以我们需要重写一个返回值为void方法来进行递归。


🍅2.迭代解法


             迭代其实也是利用了栈,只不过我们需要显示的去使用,这里我们用ArrayDeque充当栈比直接使用Statck更好。还要注意为什么先把右子节点入栈再入左子节点呢?因为栈是先进后出,前序遍历是中左右,为了让左节点先出所以得先放入右子节点。


class Solution {
    //用来存放答案的list
    List<Integer> list=new ArrayList<>();
    //用来当栈
    Deque<TreeNode> statck=new ArrayDeque<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root==null) return list;
        //先放入根节点
        statck.push(root);
        while(!statck.isEmpty()){
            //每次循环前先出栈一个元素
            TreeNode node=statck.pop();
            //然后加入到list中
            list.add(node.val);
            //再把该元素的右节点放入(空节点不如栈)
            if(node.right!=null){
                statck.push(node.right);
            }
            //再把左节点放入(空节点不如栈)
            if(node.left!=null){
                statck.push(node.left);
            }
        }
        return list;
    }
}


🍈 2.二叉树的中序遍历(左中右)


给定一个二叉树的根节点 root ,返回它的 中序 遍历。


题目链接:二叉树的中序遍历https://leetcode-cn.com/problems/binary-tree-inorder-traversal/


🍈1.递归解法


              代码和前序遍历差不多一样,只需要换一下顺序即可,可与前面的代码对照

class Solution {
    List<Integer> list=new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
            if(root==null) return list;
            test(root);
            return list; 
    }   
    public void test(TreeNode root){
        if(root==null) return;
        //这里我们先处理左子节点
        test(root.left);
        //再把跟节点放入到集合中
        list.add(root.val);
        //再处理右子节点
        test(root.right);
    }
}


相关文章
|
5月前
|
Java
java基础(11)函数重载以及函数递归求和
Java支持函数重载,即在同一个类中可以声明多个同名方法,只要它们的参数类型和个数不同。函数重载与修饰符、返回值无关,但与参数的类型、个数、顺序有关。此外,文中还展示了如何使用递归方法`sum`来计算两个数之间的和,递归的终止条件是当第一个参数大于第二个参数时。
44 1
java基础(11)函数重载以及函数递归求和
|
4月前
|
Java
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)
42 1
|
4月前
|
算法 Java C语言
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(一)
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(一)
37 1
|
3月前
|
算法 Java
JAVA 二叉树面试题
JAVA 二叉树面试题
35 0
|
7月前
|
算法 Java
java使用递归及迭代方式实现前序遍历 中序遍历 后序遍历 以及实现层序遍历
java使用递归及迭代方式实现前序遍历 中序遍历 后序遍历 以及实现层序遍历
104 7
|
6月前
|
存储 算法 Java
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
97 0
|
3天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
39 14
|
6天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
36 13
|
7天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
109 17

热门文章

最新文章