详见: 漫画:什么是红黑树
一. 二叉查找树(BST)
A. 原理:
二叉排序树
又称二叉查找树
,也称二叉搜索树
。
二叉查找树
或者是一棵空树
,或者是具有下列性质的二叉树
:
-
若
左子树
不空,则左子树
上所有的结点值
均小于或等于
它的根结点
的值。 -
若
右子树
不空,则右子数
上所有结点值
均大于或等于
它的根节点
的值。 -
左、右子树
也分别为二叉排序树
。
如图所示就是典型的二叉排序树
:
B. 优势:
我们试着查找下值为10
的结点
:
1. 查看根节点
为9
, 由于10
大于9
,因此查看右孩子13
:
2. 由于10
小于13
,因此查看左孩子11
:
3. 由于10
小于11
,因此查看做孩子10
,发现10
正式要查找的节点
:
这种方式正式二分查找
的思想:查找所需的最大次数
等同于二叉查找树
的高度。
在插入节点
的时候,也是利用类似的方法
,通过一层一层
比较大小,来找到新节点
适合插入的位置
。
C. 缺陷:
但尽管如此,二叉树仍然存在缺陷:
假设初始的二叉查找树只有三个节点,根节点值为9,左孩子结点值为8,右孩子结点值为12.
初始二叉查找树.png接下来我们依次插入如下五个节点:7,6,5,4,3;依据二叉查找树的特性,得到如图所示:
image.png从图可以看出查找性能
大打折扣,几乎变成线性
了。
那如何解决二叉查找树
多次插入新结点
而导致的不平衡
呢?我们的主角红黑树
应运而生。
二. 红黑树
A. 原理
红黑树
是一种自平衡
的二叉查找树
。除了符合二叉查找树
的基本特性外,还具有下列附加特性
:
1.节点是红色或黑色
2.根节点是黑色
3.每个叶子节点都是黑色的空节点(NIL节点)
4.每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
如图就是一棵典型的红黑树
:
正是因为这些规则
的限制,才保证红黑树
的自平衡
。
红黑树
从根到叶子
的最长路径
不会超过最短路径
的2倍
。
当插入
或删除
节点的时候,红黑树
的规则有可能被打破。这时候就需要做出一些调整,来继续维持
我们的规则。
B. 自平衡
什么情况下会破坏红黑树的规则,什么情况下不会破坏规则呢?
举两个简单的 🌰:
1. 向原红黑树
插入值为14
的新节点
:
如图所示,不会破坏红黑树的规则
。
2.向原红黑树
插入值为21
的新节点
:
由于父节点22
是红色节点
,因此这种情况打破了红黑树
的规则4(每个红黑树的两个子结点都是黑色)
,必须进行调整,使之重新符合红黑树
的规则。
调整的方式
有两种:变色
和旋转
旋转
又分成两种形式
: 左旋转
和右旋转
变色:
为了重新符合红黑树
的规则,尝试把红色节点
变成黑色
,或者把黑色节点
变成红色
。
下图所示是原红黑树
的一部分,需要注意节点25
并非根节点
。因为节点21
和节点22
连续出现了红色
,不符合规则4
,所以把节点22
从红色
变成黑色
。
但是凭空多出的黑色节点
打破了规则5
,所以需要继续把节点25
从黑色
变成红色
:
此时又出现了节点25
和节点27两个连续的红色节点,需要继续把
节点27从
红色变成
黑色`。
左旋转:
逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子。
如图所示:
左旋转.png图中,身为右孩子
的Y
取代了X
的位置,而X
变成了自己的左孩子
。此为左旋转
。
右旋转:
顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。
如图所示:
右旋转.png图中,身为左孩子
的Y
取代了X
的位置,而X
变成了自己的右孩子
。此为右旋转
。
C. 典型例子
我们以刚才插入节点21
的情况为例:
首先,我们需要做的就是变色
,把节点25
及其下方的节点
变色:
此时节点17
和节点25
是连续的两个红色
,如果把节点17
变成黑色节点
?这样一来不仅打破规则5
,而且根据规则2(根节点是黑色)
,也不可能把节点13
变成红色节点
。
由此可见,变色已无法解决问题,我们把节点13
看做X
,把节点17
看做Y
,像刚才的示意图那样进行左旋转
:
由于根节点
必须是黑色节点
,所以需要变色
,变色结果
如下:
这样还没结束,从图中可以看出,其中两条路径(17 -> 8 -> 6 -> NIL)
的黑色节点个数
是4
,其他路径的黑色节点个数
是3
,不符合规则5
。
这时候,我们需要把节点13
看做X
,节点8
看做Y
,像刚才示意图那样进行右旋转
:
最后根据规则变色
:
如此一来,我们的红黑树
变得重新符合规则
。这一个例子的调整过程比较复杂,经历了如下步骤:
变色 -> 左旋转 -> 变色 -> 右旋转 -> 变色
网友评论