【路漫漫其修远兮】每日数据结构与算法:红黑树

文章介绍了红黑树在服务器端高并发IOkeepalive方案中的作用,以及如何通过红黑树结构设计线程或进程的运行体与调度器。同时,阐述了红黑树的性质,包括颜色规则和平衡特性。代码示例展示了红黑树节点的定义、左右旋操作以及插入节点的过程,最后提到将学习红黑树的删除节点及B树、B+树的相关知识。
摘要由CSDN通过智能技术生成

红黑树

红黑树的实际运用

案例一、服务器端高并发IO的keep alilve方案,满足一下几个需求

  1. 每个IO都是自己的时间戳
  2. 每个IO收到自己的beat后,重置自己的定时器
  3. 若IO定时没有收到beat,则执行IO的回调函数,并重置定时器
  4. 若再次没有收到beat,销毁IO,注销定时器。

案例二、设计一个线程或者进程的运行体R与运行体调度器S的结构体

  1. 运行体R:包含运行状态{新建,准备,挂起{IO等待读,IO等待写,睡眠,延时}, 退出},运行体回调函数,回调参数

  2. 调度器S:包含栈指针,栈大小,当前运行体

  3. 调度器S:包含执行集合{就绪,延时,睡眠,等待}。

红黑树的性质

  1. 每个结点是红的或者黑的
  2. 根结点是黑的
  3. 每个叶子结点是黑的
  4. 如果一个结点是红的,则它的两个儿子都是黑的
  5. 对每个结点,从该结点到其子孙结点的所有路径上的包含相同数目的黑结点

tips:红黑树在插入一个节点之前就已经是红黑树了;红黑树的平衡指的是黑高平衡

红黑树介绍

在这里插入图片描述

红黑树的定义代码

//把红黑树的性质拎出来了
#define RBTREE_ENTRY(name, type)    \
    struct name{                    \
    struct type * right;    \
    struct type * left;     \
    struct type *parent;    \
    unsigned char color;            \
    }


typedef struct _rbtree_node { //不可复用


    KEY_TYPE key;
    void *value;    //做业务
#if 1
    struct _rbtree_node *right;
    struct _rbtree_node *left;
    struct _rbtree_node *parent;
    unsigned char color;
#else
    RBTREE_ENTRY( ,_rb_node) node;//把红黑树的性质和业务分离了
#endif


} rbtree_node;


typedef struct _rbtree {

    rbtree_node *root;
    rbtree_node *nil;

} rbtree;

红黑树通过左旋和右旋来保证稳定(黑高的稳定)

在这里插入图片描述

红黑树左右旋代码

//左旋
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
    rbtree_node *y = x->right;//定义一个节点,指向要旋转节点的右子树节点
    x->right = y->left;//将y的做子树变为X的右子树
    if (y->left != T->nil) {//判断Y的左子树不是叶子节点
        y->left->parent = x;
    }
    y->parent = x->parent;
    if (x->parent == T->nil) {
        T->root = y;
    } else if (x == x->parent->left) {
        x->parent->left = y;
    } else {
        x->parent->right = y;
    }//判断X是父节点的右数还是左树,并相应地指向Y
    y->left = x;
    x->parent = y;
    //将X变为Y的子树

}

//右旋  和左旋一样
void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
    rbtree_node *x = y->left;
    y->left = x->right;
    if (x->right != T->nil) {
        x->right->parent = y;
    }
    x->parent = y->parent;
    if (y->parent == T->nil) {
        T->root = x;
    } else if (y == y->parent->right) {
        y->parent->right = x;
    } else {
        y->parent->left = x;
    }
    x->right = y;
    y->parent = x;
}

红黑树添加节点

void rbtree_node_insert(rbtree *T, rbtree_node *z) {
    rbtree_node *x = T->root;
    rbtree_node *y = T->nil;
    while (x != T->nil) {
        y = x;
        if (z->key < x->key) {
            x = x->left;
        } else if (z->key > x->key) {
            x = x->right;
        } else {
            return;
        }
    }
    if (y == T->nil) {
        T->root = z;
    } else {
        if (y->key > z->key) {
            y->left = z;
        } else {
            y->right = z;
        }
    }
    z->parent = y;
    z->left = T->nil;
    z->right = T->nil;

    //上色,红黑树在插入之前就已经是红黑树了
    z->color = RED;//默认上红色,不改变黑高


}

插入后调整,一共有三种情况

需要保证,Z为红色且Z的父节点为红色,就可以一只向上回溯

一、叔节点是红色

在这里插入图片描述

此时只需要将父节点变为黑色,并将祖父节点变为红色,并把Z指向祖父节点

//Z本身就是红色,Z的父节点也是红色,Z的祖父节点是黑色
    while (z->parent->color == RED) {
        if (z->parent == z->parent->parent->left) {
            rbtree_node *y = z->parent->parent->right;
            if (y->color == RED) {
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;

                z = z->parent->parent;//保证Z时刻为红色
            } 

二、叔父节点是黑色,当前节点是右孩子

此时需要将Z左旋,构造出,叔父节点是黑色,且当前节点是左孩子的情况

在这里插入图片描述

if (z == z->parent->right) {
                    z = z->parent;
                    rbtree_left_rotate(T, z);
                }

三、叔父节点是黑色,当前节点是左孩子

此时改变父节点和祖父节点颜色,并把祖父进行右旋

z->parent->color = BLACK;
                z->parent->parent->color = RED;
                rbtree_right_rotate(T, z->parent->parent); //以祖父节点进行右旋

在这里插入图片描述

z->parent->color = BLACK;
                z->parent->parent->color = RED;
                rbtree_right_rotate(T, z->parent->parent); //以祖父节点进行右旋

明日计划:学习红黑树的删除节点以及B树与B+树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值