一、删除调整发生的前提
思路:删除度为2转化为删除度为0或1的节点
红色节点度只能为0(度为1的红色节点孩子只能黑色,这样不满足性质5)
黑色节点度为0时删除产生双黑,删除调整就是为了干掉双黑;黑色节点度为1时只能是红孩子,删除并染黑
- 删除红色节点,不会对红黑树的平衡产生影响
- 度为1的黑色节点,唯一子孩子,一定是红色
- 删除度为1的黑色节点,不会产生删除调整
- 删除度为0的黑色节点,会产生一个双重黑的NIL节点
- 删除调整,就是为了干掉双重黑
二、删除调整
-
双重黑节点的兄弟节点是黑色,兄弟节点的两个孩子也是黑色,父节点增加一重黑色,双重黑与兄弟节点,分别减少一重黑色。 – 黑色上浮 会把双黑颜色稀释
-
兄弟节点是黑色,并且,兄弟节点的孩子有红色
-
R(兄弟)R(右子节点),左旋,新根改成原根的颜色,将新根的两个子节点,改成黑色
分析:48颜色不确定,为了不冲突所以38一定改成黑色,左路径上黑色数量保持不变,51需要改成原38的颜色;右路径上黑色节点数量不变,72改黑;38颜色不确定,51改成原38颜色 -
R(兄弟)L(左子节点),先小右旋,对调新根与原根的颜色,转成上一种情况
-
LL同理RR
-
LR同理RL
-
-
兄弟节点是红色,通过旋转,转变成兄弟节点是黑色的情况
三、删除代码
// 删除调整有可能改变根节点的地址
Node *erase_maintain(Node *root) {
if (root->lchild->color != 2 && root->rchild->color != 2) return root; // 不调整
// 兄弟节点是红色
if (has_red_child(root)) {
int flag = 0; // 递归向下进行调整
root->color = 0; // 原根改红
if (root->lchild->color == 0) {
root = right_rotate(root); flag = 1; // 红节点的右孩子一定黑,右旋后成为双黑的兄弟
} else {
root = left_rotate(root); flag = 2;
}
root->color = 1; // 新根改黑
if (flag == 1) root->rchild = erase_maintain(root->rchild);
else root->lchild = erase_maintain(root->lchild);
return root;
}
// 兄弟节点是黑色 且兄弟节点2个孩子黑色
if ((root->lchild->color == 2 && !has_red_child(root->rchild)) ||
(root->rchild->color == 2 && !has_red_child(root->lchild))) {
root->lchild->color -= 1;
root->rchild->color -= 1;
root->color += 1;
return root;
}
// 兄弟节点是黑色 且兄弟节点有红色孩子
if (root->lchild->color == 2) {
if (root->rchild->rchild->color != 0) { // 注:root->rchild->rchild可能是NIL
root->rchild->color = 0;
root->rchild = right_rotate(root->rchild); // 小右旋
root->rchild->color = 1;
}
root = left_rotate(root); // 左侧双黑,最后一定大左旋
root->color = root->rchild->color; // 新根颜色改为原根颜色
} else {
if (root->lchild->lchild->color != 0) {
root->lchild->color = 0;
root->lchild = left_rotate(root->lchild);
root->lchild->color = 1;
}
root = right_rotate(root);
}
root->lchild->color = root->rchild->color = 1; // 2个孩子改黑
return root;
}
Node *predecessor(Node *root) {
Node *temp = root->lchild;
while (temp->rchild != NIL) temp = temp->rchild;
return temp;
}
Node *__erase(Node *root, int key) {
if (root == NIL) return NIL;
if (key < root->key) {
root->lchild = __erase(root->lchild, key);
} else if (key > root->key) {
root->rchild = __erase(root->rchild, key);
} else {
if (root->lchild == NIL || root->rchild == NIL) {
Node *temp = root->lchild != NIL ? root->lchild : root->rchild;
temp->color += root->color; // 颜色给到唯一孩子 :处理了几种情况
free(root);
return temp;
} else {
Node *temp = predecessor(root);
root->key = temp->key;
root->lchild = __erase(root->lchild, temp->key);
}
}
return erase_maintain(root); // 回溯之前进行删除条调整
}
Node *erase(Node *root, int key) {
root = __erase(root, key);
root->color = 1;
return root;
}