定义与特点
-
红黑树的目的:由于2-3查找树是一种多叉树,实现起来较为麻烦,因此产生了红黑树。红黑树的基本思想是用标准的二叉查找树(全由2-结点构成)和一些额外的信息(替换3-结点)来表示2-3查找树。我们将树中的结点(或指向该结点的链接)分成两种类型:
- 红链接:将两端的两个2-结点链接起来构成一个3-结点
- 黑链接:2-3树中的普通链接
红结点:将该红结点和其父结点(黑结点)链接起来构成一个3-结点
黑结点:2-3树中的2-结点 -
红黑树的两种定义:
- 定义一(链接相关):通常用于和2-3查找树相联系
- 红链接均为左链接 ——《算法》中的定义(便于旋转和转换成2-3查找树)
- 没有任何一个结点同时和两条红链接相连(即从每个叶子结点到根的所有路径上不能有两个连续的红色节点)
- 该树是完美黑色平衡树,即从任意结点向下出发的任意路径的黑链接数量相同
-
定义二(结点相关):更通用的定义,之后的插入和删除都加上该定义(相当于2-3-4查找树——其中4结点表示黑结点的两个子结点为红色)
- 结点是红色或黑色的
- 更结点是黑色的
- 所有叶子结点(空结点)都是黑色的
- 从每个叶子结点(空结点)到根的所有路径上不能有两个连续的红色节点(即每个红色节点必须有两个黑色的子节点)
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点
- 定义一(链接相关):通常用于和2-3查找树相联系
-
每棵2-3查找树都对应一棵红黑树,反之亦然
- 选择并换色后,旋转子树的黑色结点数量通常不变
2-3查找树和红黑树插入方法比较
2-3查找树 | 红黑树(第一种定义的情况) |
---|---|
向2-结点插入新值 | 将一个红结点插入黑结点的左(右)链接 |
向一棵只含有一个3-结点的树(不含2-结点)插入新值 | 将一个红结点插入红结点(其父结点为黑根结点)的左(右)链接 |
向一个父结点为2-结点的3-结点插入新值 | 将一个红结点插入红结点(其父结点为黑结点,其爷爷结点为黑结点)的左(右)链接 |
向一个父结点为3-结点的3-结点插入新值 | 将一个红结点插入红结点(其父结点为黑结点,其爷爷结点为红结点,其太爷爷结点为黑结点)的左(右)链接 |
红黑树的插入操作
-
基本概念:假设增加的结点总是初识为红色
- 性质1总是保持的
- 性质3只有在插入结点为根结点的情况下才会被破坏
- 性质4只在增加红色结点、重绘黑色结点为红色、或做旋转时受到威胁(此时常用的解决办法是重绘黑色或旋转)
- 性质5只在增加黑色结点、重绘红色结点为黑色、或做旋转时受到威胁(此时常用的解决办法是交换参与旋转的两个结点的颜色)
-
一般情况下的三种情况(
N
是待插入结点,U
是N
的叔叔结点):N
的叔叔U
是红色的N
的叔叔U
是黑色的,且N
是右孩子N
的叔叔U
是黑色的,且N
是左孩子
插入的五种情况
- 新节点
N
位于树的根上,没有父节点
- 问题:此时破坏了性质2
- 解决方法:重绘该结点为黑色(维护了性质2)
- 新节点
N
的父节点P
是黑色
- 问题:无(性质4和5都没有被破坏)
- 解决方法:不做任何操作(直接插入)
-
新节点
N
的父节点P
和叔父节点U
二者都是红色- 问题:破坏了性质4
-
解决方法:
- 将
P
重绘为黑色(维护了性质4,但破坏了性质5) - 将
U
重绘为黑色并重绘祖父节点G
为红色(维护了性质5,但重绘后仍有可能破坏性质4,因此需要进行递归调节)
- 将
-
父节点
P
是红色而叔父节点U
是黑色或缺少,并且新节点N
是其父节点P
的左子节点而父节点P又是其父节点G
的左子节点(若为右子结点,则该情况的所有左右都对调)- 问题:破坏了性质4
-
解决方法:
- 针对祖父节点
G
的一次右旋转(破坏了性质5) - 交换
P
和G
的颜色(维护了性质4和性质5)
- 针对祖父节点
-
父节点
P
是红色而叔父节点U
是黑色或缺少,并且新节点N
是其父节点P
的右子节点而父节点P又是其父节点G
的右子节点(若为左子结点,则该情况的所有左右都对调)- 问题:破坏了性质4
-
解决方法:
- 进行一次左旋转调换新节点和其父节点的角色,使其变成情况4
- 按情况4的方法进行调节
总结:执行任何操作后都检查有没有破坏其中任意一个性质
红黑树的删除操作
-
二叉树删除操作的实现
- 若被删除结点的度为0,则直接删除该结点即可
- 若被删除结点的度为1,则直接删除该结点,并用该结点的子结点顶替
- 若被删除结点的度为2,则将该结点的前驱或后继结点值替换该结点的值,再删除原前驱或后继结点
-
因为度为2的结点的前驱结点和后继结点的度必定小于2,因此如果需要删除的节点有两个儿子,那么问题可以被转化成删除另一个只有一个儿子的节点的问题。所以我们只需要讨论删除只有一个儿子的节点(实际删除的结点)即可。
删除的八种情况
-
若被删除结点为红色
- 问题:无 —— 由于红黑树的性质,该结点的父结点和子结点必定为黑色,此时性质3、4、5都不会被破坏
- 解决方法:简单的用它的黑色儿子来替换它即可
-
若被删除结点为黑色,而它的儿子结点是红色
- 问题:如果只是去除这个黑色节点,用它的红色儿子顶替上来的话,不仅会破坏性质5,还有可能会破坏性质4
- 解决方法:重绘它的儿子为黑色并替换(等价于删除3-结点中的一个键)—— 这样即可维持性质5,也可维持性质4
-
若被删除结点为黑色,而它的儿子结点
N
也是黑色我们首先把要删除的节点替换为它的儿子。出于方便,称呼这个儿子为
N
(在新的位置上),称呼它的兄弟(替换后的新的父亲结点的另一个儿子)为S
。在下面的示意图中,我们还是使用P
称呼N
的父亲,SL
称呼S
的左儿子,SR
称呼S
的右儿子。以下为删除后的调整阶段:- 若
N
是新的根结点
- 问题:无 —— 因为这种情况下原先被删除的结点必定为根节点,所有路径都去除了一个黑色节点,而新根是黑色的,所以所有性质都没有被破坏
- 解决方法:不进行任何调整
-
若
S
是红色结点- 问题:破坏了性质5 —— 在这种情形下我们在
N
的父亲上做左旋转,把红色兄弟转换成N
的祖父,我们接着对调N
的父亲和祖父的颜色(使N
有了一个黑色的兄弟和一个红色的父亲,但此时所有路径上黑色节点的数目没有改变)。接着按情形3.4、情形3.5或情形3.6来处理。 - 解决方法:在
N
的父亲上做左旋转,把红色兄弟转换成N
的祖父,我们接着对调N
的父亲和祖父的颜色(使N
有了一个黑色的兄弟和一个红色的父亲)。接着按情况3.4或3.5或3.6来处理
- 问题:破坏了性质5 —— 在这种情形下我们在
-
若
N
的父亲P
、N
的兄弟S
以及S
的儿子SL
、SR
都是黑色结点- 问题:破坏了性质5 —— 若我们简单的重绘
S
为红色,结果是通过P
的所有路径的黑色结点数相同,但都比不通过P
的路径少了一个黑色节点,所以仍然违反性质5。此时可以把该问题看成是在P
和它的父结点之间原本还有一个黑结点,但被删除了(此时P
为删除结点的儿子结点),因此可以从情形1(黑根结点)开始,在P
上做重新平衡处理。 - 解决方法::重绘
S
为红色,并且从情形1(黑根结点)开始,在P
上做重新平衡处理。
- 问题:破坏了性质5 —— 若我们简单的重绘
-
若
N
的兄弟结点S
以及S
的儿子结点(SL
和SR
)都是黑色,但N
的父亲结点P
是红色- 问题:破坏了性质5 —— 交换
N
的兄弟S
和父亲P
的颜色(这不影响不通过N
的路径的黑色节点的数目,但是它在通过N
的路径上对黑色节点数目增加了一,添补了在这些路径上删除的黑色节点) - 解决方法:交换
N
的兄弟S
和父亲P
的颜色
- 问题:破坏了性质5 —— 交换
-
若
N
的兄弟结点S
为红色,S
的左儿子结点SL
为红色,右儿子结点SR
为黑色- 问题:性质5依旧被破坏 —— 在
S
上做右旋转(使S
的左儿子SL
成为S
的父亲和N
的新兄弟),接着交换S
和它的新父亲的颜色(此时该旋转子树中的所有路径仍有同样数目的黑色节点,此举的目的是使N
有一个黑色兄弟,且该兄弟结点的右儿子是红色的,但N
和它的父亲P
都不受这个变换的影响),最后进入了情形3.6。 - 解决方法:在
S
上做右旋转,接着交换S
和它的新父亲的颜色,最后进入了情形3.6
- 问题:性质5依旧被破坏 —— 在
-
若
S
是黑色,S
的右儿子SR
是红色,而N
是它父亲P
的左儿子- 问题:破坏了性质5 —— 在
N
的父亲P
上做左旋转,这样S
成为P
的父亲。我们接着交换P
和S
的颜色,并使S
的右儿子(SR
)为黑色(此时N
现在增加了一个黑色父亲,所以通过N
的所有路径都增加了一个黑色节点,而不通过N
的所有路径上的黑色节点数目都没有改变) - 解决方法:在
N
的父亲P
上做左旋转,接着交换P
和S
的颜色,并使S
的右儿子(SR
)为黑色
- 问题:破坏了性质5 —— 在
- 若