和上篇介绍的 AVL 树同样,红黑树也是一种自平衡的二叉查找树,经过以前的学习咱们知道,自平衡的二叉查找树是高效的,它能够在时间复杂度为 O(log n)下作查找、插入和删除。红黑树具有以下性质:git
下面是红黑树的例子:github
红黑树复杂的地方主要在于对其执行增删操做会破坏上面的红黑属性,所以要有相应的机制恢复。这里的恢复机制除了在介绍 AVL Tree 时讲到的旋转,还多了一种从新着色
,顾名思义,把红色变成黑色,黑色变成红色便可,在下面的介绍中会具体讲到。学习
先看下红黑树插入的状况,红黑树的插入思路是先按照二叉查找树插入的操做(具体思路请看这篇)插入节点,再经过从新着色或者旋转的方法恢复红黑属性。规定了新增的节点颜色为红色
(若是设为黑色,就会致使根到叶子的路径上有一条路上,多一个额外的黑节点,这个是很难调整的。)可是设为红色节点后,可能会致使出现两个连续红色节点的冲突,所以插入操做主要是解决上面的红黑属性 2 。下面为总结的 4 种插入情景及对应调整 “套路”,插入时检查叔叔
的颜色,假设 z 为新插入的节点,3d
基于这 4 点举例分析红黑树插入的状况,先插入节点 15:code
因为 15 是根节点,知足套路 1 ,所以将其由红色置为黑色;再相继插入 五、1:cdn
插入节点 1 后知足套路 3 ,这里先对节点 15 右旋,再从新着色即恢复红黑属性。blog
再看下一个稍微复杂的例子,对下面这棵红黑树插入节点 10:get
此时知足套路 4,将父节点 15 右旋:it
此时知足套路 3,左旋爷爷节点 8 ,再对 8 和 12 从新着色即恢复红黑属性。io
与插入相同,红黑树的删除思路是先按照二叉查找树删除的操做(具体思路请看这篇)删除节点,再经过从新着色或者旋转的方法恢复红黑属性。插入操做主要是违反了上面提到的红黑属性 2 ,而删除操做是违反了红黑属性 3 。在插入操做中,根据叔叔的颜色来选择适当的 “套路” ,在删除操做中,主要依据兄弟
的颜色 。设 X 是要删除的节点,Y 是替换树中 X 的节点,S 为 X 的兄弟。
I. X 和 Y 中有一个为红色 -> 将 Y 置为黑色
。
来看下例子,在下面的红黑树中要删除节点 30 :
再看下面这个例子,在下面的红黑树中要删除节点 30 :
II. X 和 Y 都是黑色。
接下来的情景比较特殊,引入双黑色的概念。双黑色是指:当黑色节点被删除并被黑色孩子替换时,孩子被标记为双黑色。
被标记为双黑色的节点,所在的路径黑色节点数量加 1 。共有如下这么几种状况:
a) 兄弟 S 是黑色,S 的孩子至少有一个是红色
,假设 R 是 S 的红色子节点,根据 R 和 S 的位置能够分为下面四种状况:
a1 . 右右:S 是其父亲的右节点,R 是 S 的右节点。
a2 . 右左:S 是其父亲的右节点,R 是 S 的左节点。
a4 . 左右:S 是其父亲的左节点,R 是 S 的右节点。
举个例子,在下面的红黑树中删除节点 5 :
删后以下:
b) 兄弟 S 是黑色,S 的孩子都是黑色。
解决方案:若是父节点为黑色,则置为双黑色,;若是父节点为红色,则置为黑色;S 置为红色;若根节点为双黑色时,置为黑色。
举个例子,在下面的红黑树中删除节点 10 :
首先经过二叉查找树的遍历方法找到 10 ,遍历右子树,用 20 代替,再删除 20 ,删完以下:
上面的图偷懒了,咱们知道空节点默认是黑色的,因此完整的图应该是这样的:
此时不知足红黑属性 3 ,从根节点 10 到其余空叶子节点通过的黑色节点数量为 3 ,而到 z 这条路径通过的黑色节点数量为 2 ,将 z 置为双黑色,这样就平衡了:
接下来就是解决双黑色的问题了,将 38 置为红色,将 30 置为黑色即恢复红黑树 :
下面的红黑树中删除节点 10
删后以下:
将 40 置为红色,并把 30 置为双黑色:
因为节点 30 是根节点,因此直接去掉节点 30 外圈加的黑色:
c) 兄弟 S 是红色。
按照 S 的位置又分为下面两种状况
c1. 右侧:S 是右子节点:
c2. 左侧:S 是左子节点:
Enjoy –☺