文章目录
一:什么是红黑树
红黑树是AVL树的一种流行变种,是具有以下五个特点的二叉查找树:
- 每一个节点或者着成红色,或者着成黑色
- 根是黑色
- 每个叶节点Nil是黑色
- 如果一个节点是红色的,那么它的子节点必须是黑色的
- 每一条从某节点到某Nil指针的路径必须包含相同数目的黑色节点
二:关于红黑树的一般操作
对红黑树操作,最困难的就是保持上述的红黑树性质中的红色标记部分。
1.查找操作
红黑树是二叉查找树,所以其查找操作与一般的二叉查找树相同
- 令根节点为当前节点
- 当前节点为Nil,返回Nil
- 要找的值等于当前节点,返回当前节点
- 要找的值大于当前节点, 令右儿子为当前节点,重复步骤2
- 要找的值小于当前节点,令左儿子为当前节点,重复步骤2
操作的时间复杂度O(logN)
2. 插入操作
当我们想向树中插入一个新节点时,通常把这个节点作为叶节点插入。
Part1:
假设把这个点涂成黑色,那完了,肯定违反了条件5,因为本来任意的节点到某Nil指针的路径中黑色节点数是相同的,现在加上黑色节点的这条路径黑色节点数度肯定会+1,于是原来的条件被破坏了,因此,新加的节点必须被涂成红色。
Part2:
如果新插入的节点的父节点是黑色的,那么直接插入新的红节点就完事了
Part3:
如果新插入的节点的父节点是红色,那么条件4就被破坏了,这种情况下,我们必须在保持条件5不被破坏的同时,利用改变节点颜色以及树的旋转来满足所有条件。
2.1 新节点:我是红色的,我爹是红色的,我叔叔是黑色的
- 设置P为黑色
- 设置G为红色
- 进行右单旋转
- 设置X为黑色
- 设置G为红色
- 进行右双旋转
还有对称的两种情况,操作也是对称的
2.2 新节点:我是红色的,我爹是红色的,我叔叔也是红色的
- 把G节点设置为红色
- 把P节点设置为黑色
- 把S节点设置为黑色
- 把G节点设置为红色
- 把P节点设置为黑色
- 把S节点设置为黑色
这时候,如果G的父节点也是红的,那么G的颜色翻转的操作就会影响性质4,于是我们对G节点以及其父节点GP
和父节点的兄弟节点GPS
进行2.1所示的旋转操作。
注意如果G的父节点GP
为红色,G父节点的兄弟节点GPS
肯定不能为红色,只能为黑色,因为在红黑树中,不可能出现出现深度小于树的总深度且双兄弟都为红的情况,这种情况在其他的插入或删除过程中已经消除了。
GP
刚好为根结点时,那么根据性质2,我们必须把GP
重新设为黑色,那么树的红黑结构变为:黑黑红。换句话说,从根结点到叶子结点的路径中,黑色结点增加了。这也是唯一一种会增加红黑树黑色结点层数的插入情景。
还有对称的两种情况,操作也是对称的
难点来了,难点来了!!
其实不难
3.删除操作
删除操作一直一来是树这种ADT的难点所在
一般二叉搜索树的删除操作:
- 该节点为叶节点的情况:可以直接删除,将其父节点的儿子指针设为Nil
- 该节点只有一个非空子节点:可以直接删除,将其父节点的儿子指针指向其唯一儿子
- 该节点有两个非空子节点:用该节点左子树的最大节点或者右子树的最小节点替换该节点,然后删除对应的左子树最大节点或者右子树最小节点,最终可以回到前两种情况。
好,到这里你肯定还是明白的对吧
现在考虑红黑树的删除操作。
注意:
根据一般二叉搜索树的删除操作来看,我们要删除的节点其实不一定是最终从图中移出去的节点,称最终从图中移出去的节点为替代点,我们先从右子树的最小节点(或左子树的最大节点)找到我们的替代点,与删除点的值交换,但是颜色都不变,然后再删除替代点,然后对树的性质进行恢复。而现在这些替代点都是一些树的末节点(区别于叶节点,我们现在将Nil节点视为黑色叶节点),删除操作便会简化许多,并可以归纳为像插入那样的几个类别。当然了替代点和我们要删除的点也有可能是同一点,但处理方法是一样的。
我们虽然删除了替代点,但是我们对树进行恢复时,还是会将该替代点放在树中参与恢复,恢复完成后再移掉。
在本文中,示例都默认是选择右子树的最小节点作为真正删除点,也可以选择左子树的最大节点
3.1替代点是红色的
直接从树中去掉即可,不会影响红黑树的性质,算法直接结束
不会出现替代点为红色且有儿子为非叶子节点的情况,所以这种情况是最简单的
3.2替代点是黑色的
替代点是黑色,那么删除之后树的性质就被破坏了,需要进行修复
3.2.1 有一个儿子为且必须为红色时
当替代节点只有一个儿子且为红色时
直接用它的红色儿子节点取代它,并将颜色改为黑色,这样所有经过替代节点的路径都将经过他的儿子,黑色高度不变。
注意这跟上面图不一样,这张图D节点是替代节点
不可能存在只有一个儿子且儿子为黑色的情况,那样本身就是不平衡的
3.2.2 有两个黑色儿子
当替代点是黑色的且有两个黑色儿子(可以为叶节点Nil)时,那他肯定有兄弟,那么又可以分为其他几类
- 替代点是黑色,其兄弟节点是红色
- 替代点是黑色,其兄弟节点是黑色
3.2.2.1 替代点的兄弟节点是红色
- 将G节点也就是替代点的父节点设置为红色,
- 兄弟节点S设置为黑色
- 然后进行向左单旋转,
现在可以直接删掉D了吗?(以下都默认标识D为替代点)
这个操作不改变任何路径的黑色高度,这时候删去D肯定会变的不平衡,我们只是把情况变为了兄弟节点为黑色的情况,也就是下面将要叙述的情况,我们接下来需要重新进入算法,进一步处理
3.2.2.2 替代点的兄弟节点是黑色
替代点D与其兄弟节点S都是黑色的,所以D的父节点颜色是不确定的,用绿色表示
又分为以下几种情况
3.2.2.2.1 当兄弟节点的两个儿子也都是黑色
PS:C1、C2可为Nil
- S节点颜色变为红
- G节点颜色变黑
- 把P作为新的替代点
假设G一开始是黑色的,这个操作过后,所有一开始经过S节点的路径黑色高度-1,那么在删除D后,所有经过D节点的路径黑色高度也会-1,结局竟该死的甜美,但是经过G的比不经过G的黑色高度减一了,所以再在G上重新平衡处理
假设G一开始是红色的,这个操作后,所有一开始经过S节点的路径黑色高度不变,经过D的路径黑色高度+1,那么在删除D后,所有经过D节点的路径黑色高度又变回来了,结局竟还是该死的甜美,经过G为根的子树已经平衡了,再在G上重新平衡处理
注意当G是树的根时,就表示我们已经做完了,我们从所有路径去除了一个黑色节点,所有性质在上溯过程中都保持着。
3.2.2.2.2 当兄弟节点的左儿子是红色的,右儿子是黑色
- C1设置为黑色
- S设置为红色
- 对S进行向右单旋转
这样的操作不改变任何路径的黑色高度,本来的平衡状态不变,所以删除D之后就破坏了原先的条件,还要进行自平衡变换,此时成了下面一种情况继续处理
3.2.2.2.3 当兄弟节点的右儿子是红色的,左儿子随意
- 交换G和S的颜色
- 设置兄弟节点的右儿子C2为黑色
- 进行向左单旋转
该操作使所有变化前经过S节点的路径黑色高度都不变,经过D的路径黑色高度+1,在删除D后,所有经过G节点的路径都不变,达到平衡
说白了删除就是不断递归变换直到满足替代点的删除条件。
例子:删除30根节点
三:渐进边界的证明
包含n个内部节点的红黑树的高度是
定义: