添加节点一共有12种情况,只需要把12种情况处理好就行。
一、添加节点
B树中,新元素必定是添加到叶子节点中。4阶B树所有节点的元素个数x
都符合1 ≤ x ≤ 3
,所以建议新添加的节点默认为RED
,这样能够让红黑树的性质尽快满足(性质 1、2、3、5 都满足,性质 4 不一定)。
如果添加的是根节点,染成BLACK
即可。
以下有4种情况满足红黑树的性质4:parent
为BLACK(同样也满足4阶B树的性质(黑色节点和红色子节点合并为超级节点),因此不用做任何额外处理)。
以下有8种情况不满足红黑树的性质4:parent
为RED(连个连续的红色,违背红黑树性质)。其中前4种属于B树节点上溢的情况。
1.1. 修复性质4 – LL\RR
如上图中的新增的52和60节点,不满足红黑树。如果把46(黑)-50(红)-52(红)
看作一棵B树子树,要想让46-50-52
合并在一个节点中,需要把50(红)
染成50(黑)
,把46(黑)
染成46(红)
,这样才可以合并成一个B树节点46(红)-50(黑)-52(红)
。同理,把60(红)-72(红)-76(黑)
染成60(红)-72(黑)-76(红)
。
但是在B树中,黑色节点永远是父节点,所以我们还需要对祖父节点进行旋转。
实现思路:
判定条件:uncle
不是RED
parent
染成BLACK,grand
染成REDgrand
进行单旋(LL/RR)操作
1.2. 修复性质4 – LR\RL
如上图中的新增的48和74节点,不满足红黑树。但根据上面的单旋处理方法,我们也可以对新增节点的父节点和祖父节点进行LR/RL。例如对50进行右旋,再对46进行左旋,此时48就是46和50的父节点,所以48是黑色节点,46和50是红色节点。同理对新增的74节点树进行LR,然后对节点着色。
实现思路:
判定条件:uncle
不是RED
- 自己染成BLACK,
grand
染成RED - 进行双旋(LR/RL)操作
为什么要判断
uncle
是不是RED?因为8种情况的前4种新增节点的uncle
节点都是RED,而后4种新增节点的uncle
不是红色(空节点是黑色)。
1.3. 修复性质4 – 上溢 – LL
把17-25-33
看作一个B树,而4阶B树最多存储3个元素,如果继续往该节点新增节点10,就会出现上溢。解决上溢就需要把中间的元素(17或25)取出向上合并,我们选择把节点25向上合并,因为节点25本身就是节点38的子节点,并且分割节点也更加容易(17和33本身就是25的子节点)。然后把分割子节点为10-17
和33
,同时为了满足红黑树的性质,节点38也需要染成黑色,节点25染成红色,节点17和节点33染成黑色。节点25向上合并会引发节点38和节点55的染色情况,所以把节点25作为新添加的元素(染成红色)来处理即可。
实现思路:
判定条件:uncle
是RED
parent、uncle
染成BLACKgrand
向上合并,并且染成RED,当做是新添加的节点进行处理grand
向上合并时,可能继续发生上溢,若上溢持续到根节点,只需将根节点染成BLACK
上溢是LL情况,但不需要旋转。
1.4. 修复性质4 – 上溢 – RR
RR上溢和LL上溢基本一致。
实现思路:
判定条件:uncle
是RED
parent、uncle
染成BLACKgrand
向上合并,并且染成RED,当做是新添加的节点进行处理grand
向上合并时,可能继续发生上溢,若上溢持续到根节点,只需将根节点染成BLACK
1.5. 修复性质4 – 上溢 – LR
新增节点20如果上溢,向上合并的节点25就需要染成红色,分割后的节点17和节点33需要染成黑色。
实现思路:
判定条件:uncle
是RED
parent、uncle
染成BLACKgrand
向上合并,并且染成RED,当做是新添加的节点进行处理
1.6. 修复性质4 – 上溢 – RL
RL和LR情况也基本一致。
实现思路:
判定条件:uncle
是RED
parent、uncle
染成BLACKgrand
向上合并,并且染成RED,当做是新添加的节点进行处理
1.7. 总结
添加一共有12种情况:
- 4种情况(
parent
为BLACK)- 不需要做任何处理。
- 8种情况(
parent
为RED)- 4种情况(
uncle
不是红色)- 单旋
parent
染成BLACK,grand
染成REDgrand
进行单旋(LL/RR)操作
- 双旋
- 自己染成BLACK,
grand
染成RED - 进行双旋(LR/RL)操作
- 自己染成BLACK,
- 单旋
- 4种情况(
uncle
是RED)- 上溢
parent、uncle
染成BLACKgrand
向上合并,并且染成RED,当做是新添加的节点进行处理(grand
向上合并时,可能继续发生上溢,若上溢持续到根节点,只需将根节点染成BLACK)
- 上溢
- 4种情况(
上溢合并仅仅是把对应的代码看做B树处理,但实际上不需要合并和分割,所以上溢情况仅仅是染色而已。
二、具体代码
添加的代码其实很简单,只需要把上面的几种情况列出来即可。
1 |
|
建议:红黑树(RBTree)和AVL树(AVLTree)继承一个新的类平衡二叉搜索树(BBST),BBST继承二叉搜索树(BST),BST继承二叉树(BinaryTree)。