[高级数据结构] 4. 红黑树(下)

本文详细阐述了红黑树的删除调整策略,包括删除度为2的节点、删除红色节点以及删除黑色节点的处理。删除过程中涉及的旋转操作、颜色调整和双黑节点消除等关键步骤进行了深入解析,并提供了相应的C++实现代码,展示了如何在删除节点后维持红黑树的平衡。
摘要由CSDN通过智能技术生成

一、删除调整发生的前提

思路:删除度为2转化为删除度为0或1的节点
红色节点度只能为0(度为1的红色节点孩子只能黑色,这样不满足性质5)
黑色节点度为0时删除产生双黑,删除调整就是为了干掉双黑;黑色节点度为1时只能是红孩子,删除并染黑

  1. 删除红色节点,不会对红黑树的平衡产生影响
  2. 度为1的黑色节点,唯一子孩子,一定是红色
  3. 删除度为1的黑色节点,不会产生删除调整
  4. 删除度为0的黑色节点,会产生一个双重黑的NIL节点
  5. 删除调整,就是为了干掉双重黑

二、删除调整

  1. 双重黑节点的兄弟节点是黑色,兄弟节点的两个孩子也是黑色,父节点增加一重黑色,双重黑与兄弟节点,分别减少一重黑色。 – 黑色上浮 会把双黑颜色稀释

  2. 兄弟节点是黑色,并且,兄弟节点的孩子有红色

    1. R(兄弟)R(右子节点),左旋,新根改成原根的颜色,将新根的两个子节点,改成黑色

      分析:48颜色不确定,为了不冲突所以38一定改成黑色,左路径上黑色数量保持不变,51需要改成原38的颜色;右路径上黑色节点数量不变,72改黑;38颜色不确定,51改成原38颜色

    2. R(兄弟)L(左子节点),先小右旋,对调新根与原根的颜色,转成上一种情况

    3. LL同理RR

    4. LR同理RL

  3. 兄弟节点是红色,通过旋转,转变成兄弟节点是黑色的情况

三、删除代码

// 删除调整有可能改变根节点的地址
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值