✅✅二叉树总结篇 (上)

187 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情🚀🚀

前言

二叉树这里是个大章节,经过这十天训练营刷题,又把代码随想录上二叉树的题型又给过了一遍。自己给自己打分,十分满分的话,可以给自己七分吧~

有七分的原因是经过这一遍的刷题,使我已经不会再对二叉树一些中等题型畏惧了,甚至还会觉得中等题也就简单题差不多。

扣三分的原因,因为实习试用期的原因,有几天效率不是很高,有些题搞的不是那么令我满意。

不管怎么说吧,七分也达到自己的预期了~

后面就是对这十天内容的一个小梳理,小总结了~

🎉🎉🎉

二叉树的遍历

在第13天的时候,自己也写了篇文章梳理了一下,详细的话可以参考这一篇,或者直接去代码随想录阅读卡哥的。👉👉✅✅代码随想录算法训练营Day13 || 二叉树的遍历 - 掘金 (juejin.cn)

二叉树的结构

这里是基础中的基础了,我相信有很多小白和我刚开始一样,可能连二叉树结构都没搞清楚就盲目的刷题了,但这样的结果无非就是欺骗自己,以为自己会了各种各样的遍历方式,但为什么总是会忘,记不牢,一大部分原因可能就是对二叉树的结构都没搞懂~

其实就是说我自己了~🤪🤪

一颗普通的二叉树 image.png 有着不普通的结构

    const root = {
      val: "A",
      left: {
        val: "B",
        left: {
          val: "D"
        },
        right: {
          val: "E"
        }
      },
      right: {
        val: "C",
        right: {
          val: "F"
        }
      }
    };

可以看到,其实就是对象中,val,left,right不停套娃

遍历方式

以一定的顺序规则,逐个访问二叉树的所有结点,这个过程就是二叉树的遍历。按照顺序规则的不同,遍历方式有以下四种:

  • 先序遍历
  • 中序遍历
  • 后序遍历
  • 层次遍历

按照实现方式的不同,遍历方式又可以分为以下两种:

  • 递归遍历(先、中、后序遍历)
  • 迭代遍历(层次遍历)

具体就不展开说了,因为真的很基础!!总结这里只想说一下注意点。

递归函数要点

编写一个递归函数之前,大家首先要明确两样东西:

  • 递归边界
  • 递归式

拿先序遍历举例

// 所有遍历函数的入参都是树的根结点对象
function preorder(root) {
    // 递归边界,root 为空
    if(!root) {
        return 
    }
     
    // 递归式
    // 输出当前遍历的结点值
    console.log('当前遍历的结点值是:', root.val)  
    // 递归遍历左子树 
    preorder(root.left)  
    // 递归遍历右子树
    preorder(root.right)
 }

我在最近对这个式子有了新的感悟,就是这种递归边界就是下一层结点要处理的,下面的递归式就是接受递归边界的返回值(如果有的话),并且将递归边界递归式都写在同一个递归函数中

迭代遍历

就是利用栈实现

比如这道题,利用迭代实现 image.png 直接上代码

const preorderTraversal = function(root) {
  // 定义结果数组
  const res = []  
  // 处理边界条件
  if(!root) {
      return res
  }
  // 初始化栈结构
  const stack = [] 
  // 首先将根结点入栈
  stack.push(root)  
  // 若栈不为空,则重复出栈、入栈操作
  while(stack.length) {
      // 将栈顶结点记为当前结点
      const cur = stack.pop() 
      // 当前结点就是当前子树的根结点,把这个结点放在结果数组的尾部
      res.push(cur.val)
      // 若当前子树根结点有右孩子,则将右孩子入栈
      if(cur.right) {
          stack.push(cur.right)
      }
      // 若当前子树根结点有左孩子,则将左孩子入栈
      if(cur.left) {
          stack.push(cur.left)
      }
  }
  // 返回结果数组
  return res
};

主要:用res数组去接受stack出栈的值

入栈: 寻找存在的左右子树将其入栈

出栈:将入栈的值弹出

将弹出的结点赋给res数组

另外还要注意一下中序和后续的迭代方式和模拟队列的层序遍历写法~

二叉树的属性

1.对称二叉树:编写一个可以同时遍历根节点左右子节点的函数,比较这个课二叉树内部和外侧的节点是否相等。

2.最大深度:可以看成求最大高度,这里分递归写法,和迭代写法。

3.最小深度:和最大深度差不多,不同的地方就是最小深度的定义要明白,然后分情况讨论。

4.结点个数:随便用一种遍历方式去计数就OK了~

5.平衡二叉树:用左结点高度-右结点高度的绝对值小于等于1即可。

6.二叉树所有路径:要想清楚回溯的过程,还有->符号是如何回溯的。

7.左叶子树之和: 判断左叶子树的条件,以及后序遍历。

8.左下角的值: 层序遍历,找每一层第一个一直替换下去。

9.路径总和:主要回溯和隐藏的回溯写法。

结尾

老实说,再让我写一遍上面的题我还是有点呛,但如果能多给点时间去解上面这些问题,我还是有自信靠自己对二叉树的理解,写出个百分之八十以上的题的~

⭐⭐⭐