数据结构 之 常见的树

文章目录

树的概念

树是一种数据结构,其中以树和二叉树最为常用。它有n(n>0)个有限的节点组成一个具有层次的集合。

直观看来,树是以分支关系定义的层次结构。把它叫做"树"是因为它常看起来像一棵倒挂的树,也就是说它常是根朝上,而叶朝下的。

术语(以二叉树举例)

术语可以不用看晦涩的解释,直接结合图和下方的文字解释看就可以

  • 结点:包含一个数据元素及若干指向其子树的分支

    A、B、C、D、E、F、G、H、I、J 均为节点

  • 结点的度:一个结点拥有的子树的数目

    A、B、C、D 节点的度为2;

    G节点的度为1;

    E、F、H、I、J 节点的度为0

  • 叶子或终端结点:度为0的结点(没有分支的节点);

    E、F、H、I、J 节点为叶子节点

  • 子结点(孩子节点):结点的子树的根称为该结点的孩子结点或子结点;

  • 父结点(双亲节点):若一个结点含有子结点,则这个结点称为其子结点的双亲结点或父结点;

  • 兄弟结点:同一个双亲的孩子之间互称兄弟;

    A节点为B、C节点的父节点;B、C节点为A节点的子节点

    其中B为A的左子树(因为B在A的左分支),C为A的右子树

    B节点、C节点互为兄弟节点

  • 有序树和无序树:树中结点的各子树从左到右是有次序的,不能互换,称该树为有序树,否则称为无序树;

二叉树

  • 每个节点最多有两个子节点的树结构,‌通常被称为左子树和右子树。‌
  • 二叉树的根节点可以为空
  • 左/右子树可以为空(此时根节点不可以为空)

遍历

  • 层级遍历:由上到下一层层的来遍历树的节点

    上图的层级遍历结果:A - B - C - D - E - F - G - H - I - J

  • 前序遍历:按照【根-左-右】的顺序遍历树

    即优先遍历根节点,顺序遍历左右节点

    遍历结果:A - B - D - H - I - E - C - F - G - J

  • 中序遍历:按照【左-根-右】的顺序遍历树

    即优先遍历左节点,然后是根节点,最后是右节点

    遍历结果:H - D - I - B - E - A - F - C - J - G

  • 后序遍历:按照【左-右-根】的顺序遍历树

    即优先顺序遍历左右节点,最后遍历根节点

    遍历结果:H - I - D - E - B - F - J - G - C - A

满二叉树

  • 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树
  • 特点 1、满二叉树的深度为k,则它具有2^(k - 1)个节点。反之,如果一个二叉树的节点数是2^(k - 1),那么它的深度为k

    2、在满二叉树中,除最后一层外,每一层的节点数都达到最大值。具体来说,第i层上的节点数为2*(i-1)个。

    3、满二叉树的叶子节点(即最后一层的节点)个数为2*(k-1),其中k为树的深度

    4、在满二叉树中,除了叶子节点外,每个节点的度都为2,即每个非叶子节点都有两个子节点。

完全二叉树

  • 一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

二叉搜索树(有序二叉树)

哈夫曼树

术语补充

  • 路径和路径长度:在一棵树中,从一个节点往下可以到达的后代节点之间的通路,称为路径;通路中分支的树木称为路径的长度。若规定根节点层数为1,则从根节点到第L层节点的长度为(L-1)
  • 节点的权:若树中节点赋给一个有着某种意义的数值,则这个数值称为这个节点的权
  • 带权路径长度:从根节点到该节点之间的路径长度与该节点权的乘积
  • 树的带权的路径长度:所有叶子节点 的带权路径长度之和,记为WPL 权值越大的节点离根节点越近,WPL越小,最小的WPL树就是哈夫曼树

WPL的比较(直接上图)

哈夫曼树的构建过程

  • 1、将待构建哈夫曼树的节点从小到大进行排序
  • 2、取出节点权值最小的2个节点,组成一个新的二叉树
    (会出现多个节点值相等的情况,这时候选择哪个都可以,所以最后构建出来的哈夫曼树可能每个人都是不同的)
  • 3、 新的二叉树根节点的权值就是2个节点的权值之和
  • 4、将这课二叉树以根节点的权值大小再次排序
  • 5、重复2、3、4,直到所有数据都被处理,得到哈夫曼树 上图中就是一个普通的二叉树构建出来的哈夫曼树,比较简单,这里就不再多说了

    (不懂的可以评论留言,我再来补充过程图)

哈夫曼编码

我们知道计算机存储是以0或者1来存储的,那么,
要求:对字符串"i love baoding and you"进行编码
  • 普通编码,为什么不可以?

    上述字符串含空格一共是22个字符,每个字符8个字节,在计算机中存储起来就是22*8=176个字节
    假设我们自己设定每个字符所占空间小于8:i-01,空格-10,l-001,o-010,v-011...(0110001010011...)

    我们反编译的时候发现开始的01有,011也有,这时候就有冲突了~

    为了解决这种冲突,哈夫曼编码闪亮登场了

  • 哈夫曼编码构建思路

    • 1、按照字符出现的次数构建一棵哈夫曼树,次数作为权值
    • 2、构建哈夫曼树
    • 3、根据哈夫曼树给各个字符进行编码 规定向左为0,向右为1,那么每个子树都需要遵循该规定
  • 哈夫曼树构建结果

字符 空格 i l o v e b a d n g y u
编码 110 1001 0010 101 0011 0100 0101 1110 1111 000 0111 0110 1000
  • 可以发现任何一个字符的编码都不是其他节点的前缀
    (给想不明白的小伙伴提供个思路:我们这里要求的节点可都是叶子节点哦)

ascii编码总长度:228=176
WPL:4
3 + 24 + 1 4 + 33 + 1 4 + 14 + 1 4 + 24 + 2 4 + 23 + 1 4 + 14 + 1 4 = 79

压缩空间:176 - 79 = 97

节省:97/176 = 55.1%

非平衡树 & 平衡树(avl树)

  • 它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
  • 平衡树也适用于二分查找,虽然两边并不是完全一样,但是对于海量数据来说,多一个少一个不影响时间复杂度。

非平衡树转平衡树

  • 非平衡树转平衡树是当发现该节点不平衡了就开始转,不是树构建完毕了才会转的。
  • 直接上图吧~
  • 平衡二叉树对计算资源的损耗太大(因为发现不是平衡树需要转成平衡树)

m阶树:

  • 有(m-1)个节点,可以分出m个子树
构建一个四阶树

根非叶子节点比较大小,找到对应的叶子节点,往叶子节点上有序放数据。如果放满,就向上挤中间数,原节点裂成两个新节点,依次类推

(注意两点:有序放 高度绝对一致)


红黑树

  • 节点转红黑树的几种情况(可以结合下方图片)
    • 节点只有一个数据:该数据为黑节点
    • 节点有两个数据:有两种转换情况 高数据为黑,低数据为红,且红为黑的左子树;

      低数据为黑,高数据为红,且红为黑的右子树

    • 节点有三个数据:中间数据为黑,另两个数据为红,且按照大小分为左右子树
  • 四阶B树转成红黑树
  • 红黑树的特点
    • 1、每个节点不是红的就是黑的(红黑树嘛)
    • 2、根节点是黑色的(记住了,就是这么规定的)
    • 3、每个叶子几点都是黑色的,并且都是空节点
    • 4、如果一个节点是红色的,则它的子节点一定是黑色 如果有红色,只可能出现在第二层,下一个的开始只有黑色

      所以红色节点的子节点一定是黑色节点,黑色的节点的子节点不可能是红色节点也可能是黑色节点)

    • 5、从根节点到任意一个子节点的路径上包含了相同的黑色节点 从下往上的构建,且每个节点转换时有且仅有一个黑色节点)
    • 6、如果一条路径上有3个黑色节点,那么最长的路尽头:黑红黑红黑红黑,最短的路径:黑黑黑
    • 7、确保没有一条路径比其他路径长2倍
    • 8、时间复杂度为O(logN)
  • 应用:内存中(不害怕查找)

B树

  • 一个节点包含多个key和value值,构建时按照key排序,一个key-value构成 key表示对文件的编号;value表示页
  • m阶B树,有(m-1)个节点,可以分m个叉
  • 应用:在磁盘查找数据
    • 扩展 1、磁盘主要是用来存储数据的,原理是【电生磁】

      (磁头上有线圈,存数据时磁头根据电流方向的不同在磁盘上刻下不同的小颗粒 - N或者S极,也可以理解为0或1)

      2、磁盘由一个个的线圈来存储数据,存储的数据是由磁极N或S极来表示;

      3、磁盘读取数据很慢,大概时间是4~6毫秒(因为需要一圈圈的找到相应的磁道)

      4、磁盘读数据原理是【磁生电】

      (此时磁头线圈不带电。磁盘小颗粒周围有磁感应线,磁头划过时,线圈会感应到电流的变化,通过磁头上的感应电流的装置可以读取,然后通过导线(传递高低电压)给cpu)

      5、CPU计算一个数据大概是0.2纳秒

      6、为了缓解磁盘和CPU之间的差异,我们添加个中间层 - 内存

      7、内存,可以理解为是一个电容器,读取一个数据大概是20纳秒,但是没有稳定的电压,断电数据会消失。

      8、所有数据不能存入内存,只能存入磁盘。想让数据消失,需要磁盘消磁或者坏掉

      9、磁盘到内存之间传递数据是按页来传(如果还是按照总线数来传递01,那么内存添加就多此一举了)

      10、一页的大小大默认是4kb,可以通过x盘 - 右键 - 格式化 - 分配单元大小来设置

      11、不够4kb的单独占一页,超过4kb的多占几页

      12、所以读取数据时是磁盘按页给内存,内存交给cpu处理。这里的页就是B树中的value值

    • 优势 每个节点可以存好多值,高度低,查找的次数少

      通过编号可以很快的找到在哪页,根据页可以找到自己需要的数据

B+树

  • 非叶子节点仅具有索引的作用(只存key值,不存value)
  • B+树的所有叶子节点构成一个有序链表
  • B+树想要把整棵树遍历,只需要从头开始把叶子节点遍历一遍就行

总结

  • 一张图理解这些树
    (红黑树去掉颜色可以理解成有序的平衡树)
相关推荐
ChoSeitaku3 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程3 小时前
双向链表专题
数据结构
香菜大丸3 小时前
链表的归并排序
数据结构·算法·链表
jrrz08283 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
@小博的博客3 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
泉崎5 小时前
11.7比赛总结
数据结构·算法
你好helloworld5 小时前
滑动窗口最大值
数据结构·算法·leetcode
JSU_曾是此间年少7 小时前
数据结构——线性表与链表
数据结构·c++·算法
sjsjs117 小时前
【数据结构-合法括号字符串】【hard】【拼多多面试题】力扣32. 最长有效括号
数据结构·leetcode
blammmp8 小时前
Java:数据结构-枚举
java·开发语言·数据结构