您当前的位置: 首页 >  搜索

庄小焱

暂无认证

  • 0浏览

    0关注

    805博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

算法训练营——二叉树,二叉搜索树(第五课)

庄小焱 发布时间:2020-11-02 15:25:40 ,浏览量:0

⼆叉树的种类:满⼆叉树和完全⼆叉树。 满⼆叉树:

满⼆叉树:如果⼀棵⼆叉树只有度为0的结点和度为2的结点,并且度为0的结点在同⼀层上,则这棵⼆叉树为满⼆叉树。这棵⼆叉树为满⼆叉树,也可以说深度为k,有2^k-1个节点的⼆叉树。

完全⼆叉树

完全⼆叉树的定义如下:在完全⼆叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最⼤值,并且最下⾯⼀层的节点都集中在该层最左边的若⼲位置。若最底层为第 h 层,则该层包含 1~ 2^h -1个节点。  

⼆叉搜索树

平衡⼆叉搜索树

平衡⼆叉搜索树:⼜被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是⼀棵空树或它的左右两个⼦树的⾼度差的绝对值不超过1,并且左右两个⼦树都是⼀棵平衡⼆叉树。最后⼀棵 不是平衡⼆叉树,因为它的左右两个⼦树的⾼度差的绝对值超过了1。C++中map、 set、 multimap, multiset的底层实现都是平衡⼆叉搜索树,所以map、 set的增删操作时间时间复杂度是logn,注意我这⾥没有说unordered_map、 unordered_set, unordered_map、unordered_map底层实现是哈希表

⼆叉树的存储⽅式

⼆叉树可以链式存储,也可以顺序存储。那么链式存储⽅式就⽤指针, 顺序存储的⽅式就是⽤数组。顾名思义就是顺序存储的元素在内存是连续分布的,⽽链式存储则是通过指针把分布在散落在各个地址的节点串联⼀起。

链式存储是⼤家很熟悉的⼀种⽅式,那么我们来看看如何顺序存储呢?其实就是⽤数组来存储⼆叉树,顺序存储的⽅式如图:

⼆叉树的遍历⽅式

⼀些同学⽤做了很多⼆叉树的题⽬了,可能知道前中后序遍历,可能知道层序遍历,但是却没有框架。我这⾥把⼆叉树的⼏种遍历⽅式列出来,⼤家就可以⼀⼀串起来了。⼆叉树主要有两种遍历⽅式:

  • 1. 深度优先遍历:先往深⾛,遇到叶⼦节点再往回⾛。
  • 2. ⼴度优先遍历:⼀层⼀层的去遍历。

那么从深度优先遍历和⼴度优先遍历进⼀步拓展,才有如下遍历⽅式: 深度优先遍历

  • 前序遍历(递归法,迭代法)
  • 中序遍历(递归法,迭代法)
  • 后序遍历(递归法,迭代法)

⼴度优先遍历

  • 层次遍历(迭代法)

在深度优先遍历中:有三个顺序,前中后序遍历, 有同学总分不清这三个顺序,经常搞混,我这⾥教⼤家⼀个技巧。这⾥前中后,其实指的就是中间节点的遍历顺序,只要⼤家记住 前中后序指的就是中间节点的位置就可以了。看如下中间节点的顺序,就可以发现,中间节点的顺序就是所谓的遍历⽅式:

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中

最后再说⼀说⼆叉树中深度优先和⼴度优先遍历实现⽅式,我们做⼆叉树相关题⽬,经常会使⽤递归的⽅式来实现深度优先遍历,也就是实现前中后序遍历,使⽤递归是⽐较⽅便的。之前我们讲栈与队列的时候,就说过栈其实就是递归的⼀种是实现结构,也就说前中后序遍历的逻辑其实都是可以借助栈使⽤⾮递归的⽅式来实现的。⽽⼴度优先遍历的实现⼀般使⽤队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能⼀层⼀层的来遍历⼆叉树。这⾥其实我们⼜了解了栈与队列的⼀个应⽤场景了

⼆叉树是⼀种基础数据结构,在算法⾯试中都是常客,也是众多数据结构的基⽯。本篇我们介绍了⼆叉树的种类、存储⽅式、遍历⽅式以及定义,⽐较全⾯的介绍了⼆叉树各个⽅⾯的重点,帮助⼤家扫⼀遍基础。说道⼆叉树,就不得不说递归,很多同学对递归都是⼜熟悉⼜陌⽣,递归的代码⼀般很简短,但每次都是⼀看就会,⼀写就废。

这⾥帮助⼤家确定下来递归算法的三个要素。 每次写递归,都按照这三要素来写,可以保证⼤家写出正确的递归算法!

  • 1. 确定递归函数的参数和返回值:确定哪些参数是递归的过程中需要处理的,那么就在递归函数⾥加上这个参数, 并且还要明确每次递归的返回值是什么进⽽确定递归函数的返回类型。
  • 2. 确定终⽌条件:写完了递归算法, 运⾏的时候,经常会遇到栈溢出的错误,就是没写终⽌条件或者终⽌条件写的不对,操作系统也是⽤⼀个栈的结构来保存每⼀层递归的信息,如果递归没有终⽌,操作系统的内存栈必然就会溢出。
  • 3. 确定单层递归的逻辑:确定每⼀层递归需要处理的信息。在这⾥也就会重复调⽤⾃⼰来实现递归的过程。
求二叉树的属性
  • 二叉树:是否对称
    • 递归:后序,比较的是根节点的左子树与右子树是不是相互翻转
    • 迭代:使用队列/栈将两个节点顺序放入容器中进行比较
  • 二叉树:求最大深度
    • 递归:后序,求根节点最大高度就是最大深度,通过递归函数的返回值做计算树的高度
    • 迭代:层序遍历
  • 二叉树:求最小深度
    • 递归:后序,求根节点最小高度就是最小深度,注意最小深度的定义
    • 迭代:层序遍历
  • 二叉树:求有多少个节点
    • 递归:后序,通过递归函数的返回值计算节点数量
    • 迭代:层序遍历
  • 二叉树:是否平衡
    • 递归:后序,注意后序求高度和前序求深度,递归过程判断高度差
    • 迭代:效率很低,不推荐
  • 二叉树:找所有路径
    • 递归:前序,方便让父节点指向子节点,涉及回溯处理根节点到叶子的所有路径
    • 迭代:一个栈模拟递归,一个栈来存放对应的遍历路径
  • 二叉树:递归中如何隐藏着回溯
    • 详解二叉树:找所有路径中递归如何隐藏着回溯
  • 二叉树:求左叶子之和
    • 递归:后序,必须三层约束条件,才能判断是否是左叶子。
    • 迭代:直接模拟后序遍历
  • 二叉树:求左下角的值
    • 递归:顺序无所谓,优先左孩子搜索,同时找深度最大的叶子节点。
    • 迭代:层序遍历找最后一行最左边
  • 二叉树:求路径总和
    • 递归:顺序无所谓,递归函数返回值为bool类型是为了搜索一条边,没有返回值是搜索整棵树。
    • 迭代:栈里元素不仅要记录节点指针,还要记录从头结点到该节点的路径数值总和
二叉树的修改与构造
  • 翻转二叉树
    • 递归:前序,交换左右孩子
    • 迭代:直接模拟前序遍历
  • 构造二叉树
    • 递归:前序,重点在于找分割点,分左右区间构造
    • 迭代:比较复杂,意义不大
  • 构造最大的二叉树
    • 递归:前序,分割点为数组最大值,分左右区间构造
    • 迭代:比较复杂,意义不大
  • 合并两个二叉树
    • 递归:前序,同时操作两个树的节点,注意合并的规则
    • 迭代:使用队列,类似层序遍历
求二叉搜索树的属性
  • 二叉搜索树中的搜索
    • 递归:二叉搜索树的递归是有方向的
    • 迭代:因为有方向,所以迭代法很简单
  • 是不是二叉搜索树
    • 递归:中序,相当于变成了判断一个序列是不是递增的
    • 迭代:模拟中序,逻辑相同
  • 求二叉搜索树的最小绝对差
    • 递归:中序,双指针操作
    • 迭代:模拟中序,逻辑相同
  • 求二叉搜索树的众数
    • 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合
    • 迭代:模拟中序,逻辑相同
  • 二叉搜索树转成累加树
    • 递归:中序,双指针操作累加
    • 迭代:模拟中序,逻辑相同
二叉树公共祖先问题
  • 二叉树的公共祖先问题
    • 递归:后序,回溯,找到左子树出现目标值,右子树节点目标值的节点。
    • 迭代:不适合模拟回溯
  • 二叉搜索树的公共祖先问题
    • 递归:顺序无所谓,如果节点的数值在目标区间就是最近公共祖先
    • 迭代:按序遍历
二叉搜索树的修改与构造
  • 二叉搜索树中的插入操作
    • 递归:顺序无所谓,通过递归函数返回值添加节点
    • 迭代:按序遍历,需要记录插入父节点,这样才能做插入操作
  • 二叉搜索树中的删除操作
    • 递归:前序,想清楚删除非叶子节点的情况
    • 迭代:有序遍历,较复杂
  • 修剪二叉搜索树
    • 递归:前序,通过递归函数返回值删除节点
    • 迭代:有序遍历,较复杂
  • 构造二叉搜索树
    • 递归:前序,数组中间节点分割
    • 迭代:较复杂,通过三个队列来模拟
题目类型

二叉树的最小深度

二叉树的镜像(翻转)

二叉树是否对称

二叉树各种遍历

二叉树的打印

二叉树的重建

二叉树的路径和

二叉树是否包含子树

二叉树的公共祖先

二叉树的平衡

二叉树的深度

树为什么总是采用的是的递归的算法:因为树的结构只有的左右边的结构

关注
打赏
1657692713
查看更多评论
立即登录/注册

微信扫码登录

0.4768s