二叉树
二叉树的结构
下图为树的基本结构:
每个节点(圆圈和其内的数)中包含了四个部分:
-
父节点地址
-
数值
-
左子节点地址
-
右子节点地址
二叉树的类型
二叉查找树
特点
- 每一个节点的左子节点小于本节点
- 每一个节点的右子节点大于本节点
如何进行创建或添加
例如以下节点要构成查找二叉树:
将 7作为根节点,然后4<7,所以存到左节点,然后10>7,所以存到右节点,然后5<7,然后5就和4作比较,所以存到4的右节点;
总结:小的存左边,大的存右边,相等不存;如何查找节点
例如以下二叉树:
例如需要查找12,首先12和根节点比较,12>7,所以12再和10比较,以此类推
如果需要查找3,首先依旧和根节点比较。然后和4 比较,然后和2比较…
如何遍历二叉树
对于二叉树的遍历,有以下四种方式:
- 前序遍历
- 中序遍历
- 后序遍历
- 层序遍历
前序遍历
方式:从根节点开始,按照当前节点—>左子节点—>右子节点的顺序
eg:
遍历的结果为:20 18 16 19 23 22 24
中序遍历
方式:按照左子节点—>当前节点—>右子节点的顺序
依旧是前序遍历的例子,其结果为:16 18 19 20 22 23 24
后序遍历
方式:按照左子节点—>右子节点—>当前节点的顺序
依旧是前序遍历的例子,其结果为:16 19 18 22 24 23 20
层序遍历
方式:从根节点开始逐层遍历
依旧是前前序遍历的例子,结果为:20 18 23 16 19 22 24
平衡二叉树
由于查找二叉树会存在左右节点数量上的巨大差异,所以为了方便书写和计算,提出了平衡二叉树:
对于平衡二叉树而言,需要 遵守每个节点的左右子树的高度相差不能大于1
例如下图,此二叉树便不是平衡二叉树,因为节点10,11等的左子树高度远小于右子树的高度
平衡二叉树的平衡机制
平衡二叉树的左右旋转
当对一个平衡二叉树进行节点的添加时,会存在破坏二叉树的平衡的问题,此时便会由旋转机制来解决:
当对下个平衡二叉树添加节点12:
此时就要使用旋转机制:
从添加的节点开始,不断地寻找不平衡的父节点,例如上图,从12开始,找到的第一个不平衡的父节点是10,将此节点进行旋转(变成10的左子节点),而11节点就变为10和12节点的父节点,如下图所示:
然而面对复杂的平衡二叉树,其旋转机制需要加上一些规则来使用:
例如下图添加12节点:
此时依旧是首先寻找所添加节点的不平衡的父节点,便找到7,将此节点进行旋转(变成10的左子节点)
此时存在一个问题,原先作为10的左子节点9该去哪里,旋转机制便提出将多余的左子节点给已经降级的节点当右子节点,于是,9便成为7的右子节点,如下图所示:
然而除了这种方向向左旋转,当然可以向右旋转,方法和左旋相同;
平衡二叉树的特殊情况
当添加的节点出现在根节点左子树的右子树上
例如下图(插入的节点是6):
此时通过右旋便不可以解决,中面对这种特殊情况,我们要采取先局部旋转后大体旋转,首先以4为根节点进行一次左旋变成下图:
此时再进行右旋便可以变成平衡二叉树,如下图所示:
当添加的节点出现在根节点右子树的左子树上
原理和上一种特殊方式的处理方法一样,采用先局部旋转,后大体旋转
例如以下二叉树(添加8节点):
先进行以10节点为根节点的右旋变为:
然后进行大体上的左旋即可,如下图所示:
红黑树
红黑树是一种特殊的二叉查找树,因为每个节点上存储着节点的颜色,所以被称为红黑树
当给二叉树添加节点时,若按照平衡二叉树的规则进行添加是十分麻烦的,所以红黑树有其特殊的红黑规则,但是要知道,红黑树是二叉查找树,不是平衡二叉树;
红黑规则
- 每一个节点是红色或是黑色
- 根节点是黑色
- 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
- 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
- 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;
红黑树添加节点的规则
-
默认添加的节点是红色(改动的几率小,效率高)
-
红黑树添加节点后如何保持红黑规则
-
根节点位置—>直接变为黑色
-
非根节点位置
- 父节点为黑色:不需要任何操作,默认红色即可
- 父节点为红色:
若叔叔节点为红色:
1. 将"父节点"设为黑色,将"叔叔节点"设为黑色
2. 将"祖父节点"设为红色
3. 如果"祖父节点"为根节点,则将根节点再次变成黑色
若叔叔节点为黑色:
当前节点是父的右孩子:把父设置为当前节点进行左旋,并进行判断
当前节点是父的左孩子:
1. 将"父节点"设为黑色
2. 将"祖父节点"设为红色
3. 以"祖父节点"为支点进行旋转
例如将一下节点转化为红黑树:
20 18 23 22 17 24 19 15 16
转化后如下图所示:
-