红黑树
红黑树的实际运用
案例一、服务器端高并发IO的keep alilve方案,满足一下几个需求
- 每个IO都是自己的时间戳
- 每个IO收到自己的beat后,重置自己的定时器
- 若IO定时没有收到beat,则执行IO的回调函数,并重置定时器
- 若再次没有收到beat,销毁IO,注销定时器。
案例二、设计一个线程或者进程的运行体R与运行体调度器S的结构体
-
运行体R:包含运行状态{新建,准备,挂起{IO等待读,IO等待写,睡眠,延时}, 退出},运行体回调函数,回调参数
-
调度器S:包含栈指针,栈大小,当前运行体
-
调度器S:包含执行集合{就绪,延时,睡眠,等待}。
红黑树的性质
- 每个结点是红的或者黑的
- 根结点是黑的
- 每个叶子结点是黑的
- 如果一个结点是红的,则它的两个儿子都是黑的
- 对每个结点,从该结点到其子孙结点的所有路径上的包含相同数目的黑结点
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+树