作者的话
本内容一共分为三个部分,主要围绕Map、Set、List底层,通过增、删、改、查的方式,带大家了解最常用的一些实现类是如何实现的,如果你对集合类不太了解,可以先去学习集合篇章。本内容从2020年09月份左右开始构思,一转眼一年已经快要过去了,赶着最后一个月的时间给大家整理(详细流程操作已上传),其实主要编写还是在近三个月,白天上班晚上抽点时间熬熬夜写一写,时间久了你会发现,晚上真是一个适合创作的时间(就是有点废头发)。你可能会好奇,我前面一大部分时间干啥去了?哈哈,别问,问就是在偷懒,编写10分钟游戏两小时。你们应该也知道这是一个枯燥的过程,当然自己定的小目标,就要去实现它。好了,废话有点多。祝你学习愉快(建议将源码截图后置顶按流程图边看边思考),要是有什么地方不正确的欢迎指正。
前言
本内容主要讲解和介绍树的一些特性,帮助大家对树的结构有一个起码的认识,方便后序的Map结构讲解。
什么是树?
树是一种数据结构,它是由 n ( n > = 1 ) n(n>=1) n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下。它具有以下的特点:
- 每个节点有零个或多个子节点;
- 有且仅有一个节点的元素称为根节点;
- 每一个非根节点有且只有一个父节点;
- 除了根节点外,每个子节点可以分为多个不相交的子树。
树的常用语
- 父节点:每一个元素往上直接连接的节点称之为父节点。以下图为例:A是B的父节点,B是E的父节点。
- 子节点:反之,每一个元素往下直接连接的节点称之为子节点。以下图为例:BCD是A的子节点,EF是B的子节点。
- 根节点:没有父节点的节点称之为根节点。以下图为例:A为根节点。
- 叶子节点:反之,没有子节点的节点称之为叶子节点。以下图为例:EFCGH都是叶子节点
- 节点的度:一个节点所拥有的子节点的数,称之为节点的度。以下图为例:A节点有BCD三个节点,那么它的度为3,B节点有EF两个节点,那么它的度为2
- 树的度:所有节点中最大的度称之为数的度,以下图为例:A节点有3个度,B节点有2个度,C节点0个度,最大的度是3,那么树的度为3。
- 树的深度:一棵树有几层,就称之为树的深度,以下图为例:A为第一层,BCD为第二层,EFGH为第三层,所以树的深度为3.
什么是二叉树?
二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,左子树和右子树又同样都是二叉树,是有序树。当集合为空时,称该二叉树为空二叉树。
二叉树具有以下两个特点:
- 非空二叉树只有一个节点;
- 每个节点最多有两棵子树,且分别称为该节点的左子树和右子树
特殊二叉树
满二叉树
满二叉树的每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
如图所示:ABC每个节点都有左、右两个子节点,这样称之为满二叉树。当然也可以通过公式计算:如果一个二叉树的层数为K,且结点总数是 ( 2 k ) − 1 (2^k) -1 (2k)−1 ,则它就是满二叉树。
完全二叉树
完全二叉树除最后一层外,每一层上的节点数均达到最大值,在最后一层上只缺少右边的若干节点。
如图所示:C节点缺少了G节点,这样的树可以成为完全二叉树。如果缺少左边任意节点比如缺少D或者E节点,就只能称之为非完全二叉树。
完全二叉树和满二叉树的关系:满二叉树可以是完全二叉树,完全二叉树不能成为满二叉树
二叉树的性质
- 在二叉树的第K层上,最多有 2 K − 1 2^{K-1} 2K−1个节点。如下图:比如计算第3层上有多少个节点 2 3 − 1 = 4 2^{3-1}=4 23−1=4,所以第3层最多有4个节点。
- 深度为m的二叉树最多有 2 m − 1 2^m -1 2m−1个节点。如下图:比如树的深度为3,计算有多少个共节点 2 3 − 1 = 7 2^3-1=7 23−1=7,所以二叉树最多有7个节点。
- 度为0的节点(叶子节点)总比度为2的节点多一个。如下图:度为2的有AB两个节点,度为0的有DEF三个节点。
- 有n个节点的二叉树深度至少为
[
l
o
g
2
n
]
+
1
[log_2n]+1
[log2n]+1。
[
l
o
g
2
n
]
[log_2n]
[log2n]相当于2的多少次方(立方)等于N,使用向下取舍,能被2整除。如右图:一共有6个节点,转换为公式
[
l
o
g
2
6
]
+
1
=
2
+
1
=
3
[log_26]+1=2+1=3
[log26]+1=2+1=3,所以二叉树深度至少为3。
二叉树的遍历
所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
- 前序遍历:访问顺序为:先是根节点、再是左节点,最后右节点(简化:根左右),如图:按照遍历顺序,结果为:ABDECF
- 中序遍历:访问顺序为:先是左节点、再是根节点,最后右节点(简化:左根右),如图:按照遍历顺序,结果为:DBEAFC
- 后序遍历:访问顺序为:先是左节点、再是右节点,最后根节点(简化:左右根),如图:按照遍历顺序,结果为:DEBFCA
红黑树
- 红黑树(Red Black Tree,简称R-B Tree) 是一种自平衡二叉查找树,它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
- 红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值。
- 红黑树的每个节点上都有存储位表示节点的颜色,可以是红色(Red)或者黑色(Black)。
红黑树的特性
- 每个节点或者是黑色,或者是红色。
- 根节点是黑色。
- 每个叶子节点是黑色。 (这里叶子节点,是指为(NIL或null)的叶子节点!)
- 如果一个节点是红色的,则它的子节点必须是黑色的(也就是说不存在两个连续的红色节点)。
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。(确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。)
请牢记以上五条特性,后序讲解的所有案例都是基于此特性进行平衡。
专用名词解释
后序在讲解过程中会用看到的一些代称,可以先过一遍,有一个最初的印象。
名称 | 解释 |
---|---|
root节点 | 根节点 |
p、x节点 | 当前节点 |
xpr节点 | x节点的父节点的右子节点,简称兄弟节点 |
xpl节点 | x节点的父节点的左子节点,简称兄弟节点 |
xpp节点 | 当前节点的父节点的父节点,简称为爷爷节点 |
xppr节点 | 当前节点的父节点的父节点右子节点,简称叔节点 |
xppl节点 | 当前节点的父节点的父节点左子节点,简称叔节点 |
pl节点 | 当前节点的左子节点 |
pr节点 | 当前节点的右子节点 |
pp节点 | 当前节点的父节点 |
replacement节点 | 替换(删除)节点 |
lr节点 | 左子节点的右子节点 |
rl节点 | 右子节点的左子节点 |
next节点 | 下一个节点 |
prev节点 | 上一个节点 |
hiHead(hd) | 扩容时表示新头节点 |
hoTail(tl) | 扩容时表示新尾节点 |
loHead节点 | 原头节点 |
loTail节点 | 原尾节点 |
e节点 | 当前查找到(已存在)的节点 |
rp节点 | 右子节点的上一个节点 |
rn节点 | 右子节点下一个节点 |
first节点 | 链表中表示第一个节点 |
pred节点 | 链表中表示上一个节点 |
succ节点 | 链表中表示下一个节点 |
last节点 | 链表中表示最后一个节点 |