红黑树的插入与删除(图文理解)
一.简介
红黑树是二叉搜索树,但与平衡二叉树(AVL)相反,红黑树适用于在插入和删除操作较频繁、搜索操作相对较少的场景。
二.红黑树的性质
- 节点颜色:每个节点要么是红色,要么是黑色。
- 根节点:根节点是黑色的。
- 叶子节点(NIL节点):叶子节点是黑色的,也被称为NIL节点。它们不存储任何数据,只是作为树结构的辅助。所有指向NIL节点的指针都被认为是黑色的。
- 颜色限制:不能有两个相连的红色节点,即红色节点不能相邻,每个红色节点的子节点都是黑色的。
- 黑高度:从任意节点出发,到达其每个叶子节点的路径上的黑色节点数量必须相同,这被称为黑高度。这个性质保证了树的平衡。
三.红黑树的插入
红黑树规定,新插入的节点必须是红色的
引入概念
为方便讨论,引入概念如下
-
关注节点:当前正在处理的节点
-
数字节点:用数字序号表示的叶子节点,也就是空节点NIL
-
围绕节点X左旋:把X节点的右子树旋转上来的操作
-
围绕节点X右旋:把X节点的左子树旋转上来的操作
红黑树的插入有以下几种情况,只有**情况(4)**需要再次分类讨论 -
(1)插入节点是根节点。处理:直接插入,改变其颜色为黑色即可
-
(2)插入节点的父节点是黑色。处理:直接插入,不需要处理
-
(3)插入节点的父节点是红色,且为根节点。处理:插入,改变父节点颜色为黑色
-
(4)插入节点的父节点是红色。处理:插入,分类讨论
分类处理
插入有以下三种情况(继续分类处理的意思是,更换关注节点后,重新讨论关注节点的这三种情况)
- 情况1:关注节点N的祖父节点G是黑色,叔叔节点U是红色
处理方法:将父节点P和叔叔节点U变为黑色,祖父节点G变为红色,关注节点转为祖父节点G,继续分类处理
- 情况2:关注节点N的祖父节点G是黑色,叔叔节点U是黑色
且关注节点N与父节点P的方向不同(N为左子节点,P为右子节点等)
处理方法:围绕父节点P左旋,关注节点转为父节点P,跳到情况3
- 情况3:关注节点N的祖父节点G是黑色,叔叔节点U是黑色
且关注节点N与父节点P的方向相同(N为左子节点,P也为左子节点等)
处理方法:围绕父节点P右旋,互换P和G的颜色,处理完成
四.红黑树的删除
引入概念
红黑树的删除操作情况繁多,较为复杂。
为方便讨论,引入概念如下
- 后继节点:节点的右子树中,值最小的子节点
- 前驱节点:节点的左子树中,值最大的子节点
- 数字节点:用数字序号表示的叶子节点,也就是空节点NIL
- 紫色节点:可能是黑色,也可能是红色的节点
- R/B节点:被标记成两种颜色的节点,R:【“红-黑”】 或 B:【“黑-黑”】,(算成两个节点)
- N节点/关注节点:待删除结点
分类预处理
删除情况分类如下,**仅(4)和(5)**需要进行平衡维护:
- (1)待删除节点N为根节点。
处理方法:直接删除,无需平衡维护 - (2)待删除节点N没有子节点,若该节点为红色。
处理方法:直接删除,无需平衡维护 - (3)待删除节点N只有一个子节点C。(此节点必为红色,否则这个局部就会造成性质5的违背)
处理方法:删除N,将C变为黑色,替换到N的位置,无需平衡维护
- (4)待删除节点N没有子节点,若该节点为黑色
处理方法:直接平衡维护 - (5)待删除节点N既有左子节点又有右子节点
处理方法:找到它的前驱或后继节点进行替换(仅替换数据,不改变节点颜色和内部引用关系),则后续操作中只需要将后继节点删除即可,需要平衡维护
平衡维护
- 情况1:兄弟节点为红色,则此时父节点P和侄节点C、D必为黑色
处理方法:
若待删除节点 N 为左子节点,左旋P;若为右子节点,右旋P。
将S染黑,P染红
继续平衡维护
- 情况2:兄弟节点S和侄节点C、D均为黑色,父节点P为红色
处理方法:
此时只需将S染红,将P染黑即可
- 情况3:兄弟节点S、父节点P以及侄节点 C、D 均为黑色
处理方法:
将S染红
关注节点转为P节点,继续平衡维护
- 情况4:兄弟节点是黑色,且与N同向的侄节点C为红色,与N反向的侄节点D为黑色,父节点既可为红色又可为黑色。
处理方法:
若 N 为左子节点,右旋兄弟节点S,否则左旋兄弟节点S。
将节点 S 染红,将节点 C 染黑。
此时已满足情况5的条件,进入情况5完成平衡维护。
- 情况5:待删除节点N的兄弟节点是黑色,且与N同向的侄节点为黑色,与N反向的侄节点D为红色,父节点既可为红色又可为黑色。
处理方法:
若N为左子节点,左旋P,反之右旋P。
交换父节点P和兄弟节点S的颜色,将与N反向的侄节点D染黑
处理完毕