文章目录
- 树的概念
- 术语(以二叉树举例)
- 二叉树
- 遍历
- 满二叉树
- 完全二叉树
- 二叉搜索树(有序二叉树)
- 哈夫曼树
- 术语补充
- WPL的比较(直接上图)
- 哈夫曼树的构建过程
- 哈夫曼编码
- 非平衡树 & 平衡树(avl树)
- 非平衡树转平衡树
- m阶树:
- 构建一个四阶树
- 红黑树
- B树
- B+树
- 总结
树的概念
树是一种数据结构,其中以树和二叉树最为常用。它有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的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
二叉搜索树(有序二叉树)
- 是一个有序的树,搜索时复杂度为O(logN)
戳这里 → 查看实现代码
哈夫曼树
术语补充
- 路径和路径长度:在一棵树中,从一个节点往下可以到达的后代节点之间的通路,称为路径;通路中分支的树木称为路径的长度。若规定根节点层数为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:43 + 24 + 14 + 33 + 14 + 14 + 14 + 24 + 24 + 23 + 14 + 14 + 14 = 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+树想要把整棵树遍历,只需要从头开始把叶子节点遍历一遍就行
总结
- 一张图理解这些树
(红黑树去掉颜色可以理解成有序的平衡树)