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

【蓝桥Java每日一练】————6.二叉树的前中后序遍历(递归与迭代)二叉树的前后中序遍历 如何理解真正的递归思想 如何写出迭代的方法 如何在面试中写出更好的遍历

⭐️引言⭐️

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

⭐️精彩回放⭐️

2022.1.9——Java每日一练 【蓝桥Java每日一练】————5.按键持续时间最长的键
2022.1.8——Java每日一练 【蓝桥Java每日一练】————4.移除元素
2022.1.7——Java每日一练 【蓝桥Java每日一练】————3.合并两个有序链表
2022.1.5——Java每日一练 【蓝桥Java每日一练】————2.替换所有的问号
2022.1.4——Java每日一练 【蓝桥Java每日一练】—————1.一周中的第几天

⭐️目录⭐️

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

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

        ?1.递归解法 

        ?2.迭代解法 

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

         ?1.递归解法

         ?2.迭代解法

?3.二叉树的后序遍历(左右中)

        ?1.递归解法

        ?2.迭代解法

 ?4.关于递归以及迭代的看法


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

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

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

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

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

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

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

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

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

题目链接:二叉树的前序遍历            

        ?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 ,返回它的 中序 遍历。

题目链接:二叉树的中序遍历

         ?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); } }

         ?2.迭代解法

              有兄弟肯定觉得,你递归解法只用在前序遍历的基础上改动一下即可,那你迭代解法一样改改不就行了吗?你还真别说,这样不行!因为前序是先处理中节点也就是根节点,是比较容易操作的,而我们的中序遍历是先处理左节点完后才能一个个倒退回来处理根节点。也就是说需要先将所有的左子节点放入栈后再一个个出栈,然后才能处理中节点和右节点。

class Solution { List<Integer> list=new ArrayList<>(); Deque<TreeNode> Stack=new ArrayDeque<>(); public List<Integer> inorderTraversal(TreeNode root) { while(root!=null||!Stack.isEmpty()){ //一个while循环把左节点疯狂放入到栈中 while(root!=null){ Stack.push(root); root=root.left; } //最下面的左子节点出栈,获取他 root=Stack.pop(); //加入list中 list.add(root.val); //去处理右节点 root=root.right; } return list; } }

         我自己觉得这串代码刚开始还是有点难理解的,光说也是很难理解的,但是如果大家能用草稿纸自己画个栈debug一下,就能非常快的理解,还是希望大家开发一下动手能力多多理解。

?3.二叉树的后序遍历(左右中)

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 

题目链接:二叉树的后序遍历

        ?1.递归解法

                还是熟悉的配方还是熟悉的味道,换个位置(递归yyds)

class Solution { List<Integer> list=new ArrayList<>(); public List<Integer> postorderTraversal(TreeNode root) { test(root); return list; } public void test(TreeNode root){ if(root==null) return; test(root.left); test(root.right); list.add(root.val); } }

        ?2.迭代解法

               后序的迭代就比较有趣了,我们都知道我们写了前序的遍历顺序是中左右,在里面我们有个入栈的步骤,是先入右再入左,如果我们先入左再入右是不是遍历顺序就是中右左,这时我们把得到的答案list整个反过来,是不是就变成了左右中,也就是我们的后序遍历了。大家对比一下代码就能发现很神奇了!

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

class Solution { //用来存放答案的list List<Integer> list=new ArrayList<>(); //用来当栈 Deque<TreeNode> statck=new ArrayDeque<>(); public List<Integer> postorderTraversal(TreeNode root) { if(root==null) return list; statck.push(root); while(!statck.isEmpty()){ TreeNode node=statck.pop(); list.add(node.val); //先放左再放右 if(node.left!=null){ statck.push(node.left); } if(node.right!=null){ statck.push(node.right); } } //反转链表 Collections.reverse(list); return list; } }

 ?4.关于递归以及迭代的看法

         看到这里肯定很多兄弟觉得,那我学个递归不就行了吗,又不用变化又简单。但其实这是不对的,如果你真的理解了递归的思想,那你也是可以写出迭代的做法,如果不能,那只能说明你在生搬硬套公式而已。在现在的面试中,涉及到这类题目,面试官都回要求使用迭代的做法,因为他知道你如果能写出迭代,递归也难不倒你。所以希望兄弟们一定要掌握号迭代的做法,真正去掌握二叉树的遍历能力,去分析三者的不同。

        

       

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232330.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 中心极限与大数定理律的关系_大数定理的通俗理解(辛钦、伯努利、切比雪夫大数定理)…

    中心极限与大数定理律的关系_大数定理的通俗理解(辛钦、伯努利、切比雪夫大数定理)…大数定理简单来说 指得是某个随机事件在单次试验中可能发生也可能不发生 但在大量重复实验中往往呈现出明显的规律性 即该随机事件发生的频率会向某个常数值收敛 该常数值即为该事件发生的概率 另一种表达方式为当样本数据无限大时 样本均值趋于总体均值 因为现实生活中 我们无法进行无穷多次试验 也很难估计出总体的参数 大数定律告诉我们能用频率近似代替概率 能用样本均值近似代替总体均值 很好得解决了现实问题 大

    2025年6月8日
    2
  • 炫酷的数据可视化_人力资源看板 数据可视化

    炫酷的数据可视化_人力资源看板 数据可视化12个超炫数据可视化工具今天我们带来一篇来自Adobe工程师RohitBoggarapu的文章。他在文章中介绍了一些适合网页开发者的数据可视化和绘图工具,让你不必再花大力气与枯燥的数据抗争。部分工具不要求写代码也可以使用!我们诠释数据的方式和数据本身之间存在着巨大的鸿沟。尤其是当我们唯一的选择是盯着表格中一列列不知所云的数字时。这可能是最无聊的一种格式了。没有哪个网页开发者会喜欢电子…

    2022年9月1日
    3
  • 浅析@ResponseBody注解作用和原理

    浅析@ResponseBody注解作用和原理    @ResponseBody这个注解通常使用在控制层(controller)的方法上,其作用是将方法的返回值以特定的格式写入到response的body区域,进而将数据返回给客户端。当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。    假如是字符串则直接将字符串写到客户端,假如是一个对象,此时会将对象转化为json串然后写到客户…

    2022年5月28日
    47
  • goland 2021 激活_在线激活

    (goland 2021 激活)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html0BXA05X8YC-eyJsaWN…

    2022年3月30日
    127
  • 每天一道算法_3_487-3279_对电话号码格式化统计批处理

    早上弄了一道求高精度幂的算法,偷懒用了内部类,总觉得过意不去,所以今天重新做了一道算法题,做完心里舒服好多。题目如下: Description企业喜欢用容易被记住的电话号码。让电话号码容易被记住的一个办法是将它写成一个容易记住的单词或者短语。例如,你需要给滑铁卢大学打电话时,可以拨打TUT-GLOP。有时,只将电话号码中部分数字拼写成单词。当你晚上回到酒店,可以通过拨打310-GI

    2022年3月10日
    362
  • 实战:WEB攻击之网页脚本攻击试验

    实战:WEB攻击之网页脚本攻击试验

    2021年8月24日
    55

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号