《高级数据结构》-红黑树

《高级数据结构》-红黑树

思维导图

在这里插入图片描述

代码演示

效果

在这里插入图片描述
在这里插入图片描述

代码

/*************************************************************************
	> File Name: red_black_insert.cpp
	> Mail: 1136984246@qq.com
 ************************************************************************/

#include <stdlib.h>
#include <stdio.h>


typedef struct Node {
    int key;
    int color; // 0 : red, 1 black, 2 double black
    struct Node *lchild, *rchild;
} Node;

Node __NIL;
#define NIL (&__NIL) 

__attribute((constructor))
void init_NIL() {
    NIL->key = 0; 
    NIL->color = 1; // NIL作为叶子节点,为黑色
    NIL->lchild = NIL->rchild = NIL;
}

Node *getNewNode(int key) {
    Node *p = (Node *)malloc(sizeof(Node));
    p->key = key;
    p->color = 0; // 对于插入的话,默认插入红色
    p->lchild = p->rchild = NIL;

}

// 有无红孩子,至少有一个红孩子
int has_red_child(Node *root) {
    return root->lchild->color == 0 || root->rchild->color == 0; 
}

// 左旋:同AVL树
Node *left_rotate(Node *root) {
    Node *temp = root->rchild;
    root->rchild = temp->lchild;
    temp->lchild = root;
    return temp;
}

// 右旋
Node *right_rotate(Node *root) {
    Node *temp = root->lchild;
    root->lchild = temp->rchild;
    temp->rchild = root;
    return temp;
}

// 插入调整 
Node *insert_maintain(Node *root) {
    int flag = 0;
    if (!has_red_child(root)) return root; // 没有红孩子,不需要调整
    // 情况一:不管冲突不冲突[只要是黑红红,而不用管红下面有没有红],直接红黑黑
    if (root->lchild->color == 0 && root->rchild->color == 0) goto insert_end;
    // 情况二:需判断冲突发生在左子树,还是发生在右子树,需要使用flag进行标识
    if (root->lchild->color == 0 && has_red_child(root->lchild)) flag = 1; // 左子树发生冲突
    if (root->rchild->color == 0 && has_red_child(root->rchild)) flag = 2; // 右子树发生冲突
    // 无冲突,不调整
    if (flag == 0) return root;
    // 有冲突:旋转(同AVL) + 染色
    if (flag == 1) {
        // LR, LL
        if (root->lchild->rchild->color == 0) {
            root->lchild = left_rotate(root->lchild);
        }
        root = right_rotate(root);
    } else {
        // RL, RR
        if (root->rchild->lchild->color == 0) {
            root->rchild = right_rotate(root->rchild);
        }
        root = left_rotate(root);
    }
// 染色:采用红色上浮方式,也可才用红色下沉(此时需区分情况一还是情况二)
insert_end:
    root->color = 0;
    root->lchild->color = root->rchild->color = 1;
    return root;
}

// 插入:封装一层
Node *__insert(Node *root, int key) {
    if (root == NIL) return getNewNode(key); // 此时插入节点
    if (root->key == key) return root;
    if (key < root->key) {
        root->lchild = __insert(root->lchild, key);
    } else {
        root->rchild = __insert(root->rchild, key);
    }
    return insert_maintain(root); // 回溯的过程中进行调整
}

// 插入 + 染色[必须的,保证2nd条件:黑节点的来源]
Node *insert(Node *root, int key) {
    root = __insert(root, key);
    root->color = 1; // 手头染黑,最上面的根节点
    return root;
}


Node *predecessor(Node *root) {
    Node *temp = root->lchild;
    while (temp->rchild != NIL) temp = temp->rchild;
    return temp;
}

// 删除调整
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->lchild);
        else root->lchild = erase_maintain(root->rchild);
        return root;
    } 
    // [三种情况] : 双黑子节点的兄弟节点为黑色节点
    // [情况一]:双黑子节点的兄弟节点没有红孩子
    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) {
    // RL, RR
        root->lchild->color -= 1; // 解决双黑 [顺序无讲究]
        // 非红:可能是黑,可能是双重黑(NIL是公用的) 不用:root->rchild->rchild->color == 1 
        if (root->rchild->rchild->color != 0) {
            // RL
            // 原兄弟节点染成红色, 小右旋,新兄弟节点染成黑色
            root->rchild->color = 0;
            root->rchild = right_rotate(root->rchild);
            root->rchild->color = 1;
        } 
        root = left_rotate(root); // 大左旋(RR,RL均有)
        root->color = root->lchild->color; // 新根节点的颜色等于原根节点的颜色
    } else {
    // LR, LL
        root->rchild->color -= 1;
        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->color = root->rchild->color;
    }
    root->lchild->color = root->rchild->color = 1; // 两个新的子节点强制变成黑色

    return root;
}


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) {
            // 度为0或1 [度为0的节点删除 -> 双重黑]
            Node *temp = root->lchild != NIL ?root->lchild : root->rchild;
            temp->color += root->color; // 可处理2种情况
            free(root);
            return temp;
        } else {
            // 度为2 转化 度为0或1
            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;
}

void clear(Node *root) {
    if (root == NIL) return;
    clear(root->lchild);
    clear(root->rchild);
    free(root);
    return;
}

// 根节点的颜色 | 根节点的值,左孩子的值,右孩子的值
void print(Node *root) {
    printf("%d| %d, %d, %d\n",
        root->color, root->key,
        root->lchild->key,
        root->rchild->key
    );
}

void output(Node *root) {
    if (root == NIL) return;
    print(root);
    output(root->lchild);
    output(root->rchild);
}

int main() {
    int op, val;
    Node *root = NIL;
    while (~scanf("%d%d", &op, &val)) {
        switch (op) {
            case 1: root = insert(root, val); printf("insert %d\n", val); break;
            case 2: root = erase(root, val);  printf("erase %d\n", val); break;
        } 
        output(root);
        printf("-------------------\n");
    }
    clear(root);
    return 0;
}

参考文献

《高级数据结构》-红黑树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值