参考:https://www.jianshu.com/p/84416644c080
参考:零声学院课程
原理不说了。。。
插入的三种情况
注意需要说明的是,写代码一般是将情况三转换为情况二(以B为中心,左旋)
删除的四种情况(只涉及删除黑节点的情况,其他情况很简单的)
注意需要说明的是,写代码一般是将情况二转换为情况三(以B为中心,右旋)
代码
#include <stdio.h>
#include <stdlib.h>
//https://www.jianshu.com/p/84416644c080
// 1. 每个结点是红的或者黑的
// 2. 根结点是黑的 !!!
// 3. 每个叶子结点是黑的
// 4. 如果一个结点是红的,则它的两个儿子都是黑的 !!!
// 5. 对每个结点,从该结点到其子孙结点的所有路径上的
// 包含相同数目的黑结点
#define RED 1
#define BLACK 2
typedef int KEY_VALUE;
#define RBTREE_ENTRY(name, type)\
struct name{ \
unsigned char color; \
struct type *left; \
struct type *right; \
struct type *parent; \
}
struct rbtree_node{
RBTREE_ENTRY(,rbtree_node) rbt;
KEY_VALUE key;
};
typedef struct{
struct rbtree_node *root;
struct rbtree_node *nil;
}rbtree;
rbtree* rbtree_create(){
rbtree* T = malloc(sizeof(rbtree));
T->nil = malloc(sizeof(struct rbtree_node));
T->nil->rbt.color = BLACK;
T->nil->rbt.left = T->nil;
T->nil->rbt.right = T->nil;
T->root = T->nil;
return T;
}
void rbtree_left_rotate(rbtree *T,struct rbtree_node *x){
if(x == T->nil)
return;
struct rbtree_node *y = x->rbt.right;
if(y == T->nil)
return;
x->rbt.right = y->rbt.left;
if(y->rbt.left != T->nil)
y->rbt.left->rbt.parent = x;
y->rbt.parent = x->rbt.parent;
if(x->rbt.parent == T->nil){
T->root = y;
}else if(x == x->rbt.parent->rbt.left){
x->rbt.parent->rbt.left = y;
}else{//x == x->rbt.parent->rbt.right
x->rbt.parent->rbt.right = y;
}
y->rbt.left = x;
x->rbt.parent = y;
}
void rbtree_right_rotate(rbtree *T,struct rbtree_node *x){
if(x == T->nil)
return;
struct rbtree_node *y = x->rbt.left;
if(y == T->nil)
return;
x->rbt.left = y->rbt.right;
if(y->rbt.right != T->nil)
y->rbt.right->rbt.parent = x;
y->rbt.parent = x->rbt.parent;
if(x->rbt.parent == T->nil){
T->root = y;
}else if(x == x->rbt.parent->rbt.left){
x->rbt.parent->rbt.left = y;
}else{//x == x->rbt.parent->rbt.right
x->rbt.parent->rbt.right = y;
}
y->rbt.right = x;
x->rbt.parent = y;
}
void rbtree_insert_fixup(rbtree *T,struct rbtree_node *z){
//保持z一直是RED
while(z->rbt.parent->rbt.color == RED){
//父在左
if(z->rbt.parent == z->rbt.parent->rbt.parent->rbt.left){
//叔父在右
struct rbtree_node *y = z->rbt.parent->rbt.parent->rbt.right;
if(y->rbt.color == RED){//叔父是红
z->rbt.parent->rbt.color = BLACK;
y->rbt.color = BLACK;
z->rbt.parent->rbt.parent->rbt.color = RED;
z = z->rbt.parent->rbt.parent;
}else{//叔父不是红
if(z == z->rbt.parent->rbt.right){
z = z->rbt.parent;
rbtree_left_rotate(T,z);
}
z->rbt.parent->rbt.color = BLACK;
z->rbt.parent->rbt.parent->rbt.color = RED;
rbtree_right_rotate(T,z->rbt.parent->rbt.parent);
}
}
else{//父在右
//叔父在左
struct rbtree_node *y = z->rbt.parent->rbt.parent->rbt.left;
if(y->rbt.color == RED){//叔父是红
z->rbt.parent->rbt.color = BLACK;
y->rbt.color = BLACK;
z->rbt.parent->rbt.parent->rbt.color = RED;
z = z->rbt.parent->rbt.parent;
}else{//叔父不是红
if(z == z->rbt.parent->rbt.left){
z = z->rbt.parent;
rbtree_right_rotate(T,z);
}
z->rbt.parent->rbt.color = BLACK;
z->rbt.parent->rbt.parent->rbt.color = RED;
rbtree_left_rotate(T,z->rbt.parent->rbt.parent);
}
}
}
T->root->rbt.color = BLACK;//这
}
void rbtree_insert(rbtree *T, KEY_VALUE key){
struct rbtree_node *x = T->root;
struct rbtree_node *x_tmp = T->nil;
while(x != T->nil){
x_tmp = x;
if(x->key == key){
return;
}
else if(x->key > key){
x = x->rbt.left;
}else{//if(x->key > key)
x = x->rbt.right;
}
}
struct rbtree_node *z = malloc(sizeof(struct rbtree_node));;
z->key = key;
z->rbt.color = RED;
z->rbt.left = T->nil;
z->rbt.right = T->nil;
z->rbt.parent = x_tmp;
if(z->rbt.parent == T->nil){
T->root = z;
}else if(z->key < z->rbt.parent->key){
z->rbt.parent->rbt.left = z;
}else{//if(z->key < z->rbt.parent.key)
z->rbt.parent->rbt.right = z;
}
rbtree_insert_fixup(T,z);
}
void rbtree_delete_fixup(rbtree *T, struct rbtree_node *x){
while(x != T->root && x->rbt.color == BLACK){
if(x == x->rbt.parent->rbt.left){
struct rbtree_node *y = x->rbt.parent->rbt.right;
//兄弟是红色(父肯定不是红)
if(y->rbt.color == RED){
x->rbt.parent->rbt.color = RED;
y->rbt.color = BLACK;
rbtree_left_rotate(T,x->rbt.parent);
y = x->rbt.parent->rbt.right;
}
if(y->rbt.left->rbt.color == BLACK && y->rbt.right->rbt.color == BLACK){
y->rbt.color = RED;
x = x->rbt.parent;//兄弟是黑,父母是红,则兄弟变红,父母变黑,结束循环(其实代码是这样的,x=parent,跳出循环,再把x赋值为黑)
}else{
if(y->rbt.left->rbt.color == RED){
y->rbt.color = RED;
y->rbt.left->rbt.color == BLACK;
rbtree_right_rotate(T,y);
y = x->rbt.parent->rbt.right;
}
y->rbt.color = x->rbt.parent->rbt.color;
x->rbt.parent->rbt.color = BLACK;
y->rbt.right->rbt.color = BLACK;
rbtree_left_rotate(T,x->rbt.parent);
x = T->root;
}
}
else{//x == x->rbt.parent->rbt.right
struct rbtree_node *y = x->rbt.parent->rbt.left;
//兄弟是红色(父肯定不是红)
if(y->rbt.color == RED){
x->rbt.parent->rbt.color = RED;
y->rbt.color = BLACK;
rbtree_right_rotate(T,x->rbt.parent);
y = x->rbt.parent->rbt.left;
}
if(y->rbt.left->rbt.color == BLACK && y->rbt.right->rbt.color == BLACK){
y->rbt.color = RED;
x = x->rbt.parent;
}else{
if(y->rbt.right->rbt.color == RED){
y->rbt.color = RED;
y->rbt.right->rbt.color == BLACK;
rbtree_left_rotate(T,y);
y = x->rbt.parent->rbt.left;
}
y->rbt.color = x->rbt.parent->rbt.color;
x->rbt.parent->rbt.color = BLACK;
y->rbt.left->rbt.color = BLACK;
rbtree_right_rotate(T,x->rbt.parent);
x = T->root;
}
}
}
x->rbt.color = BLACK;
}
struct rbtree_node *rbtree_mini(rbtree *T, struct rbtree_node *x) {
while (x->rbt.left != T->nil) {
x = x->rbt.left;
}
return x;
}
struct rbtree_node *rbtree_delete(rbtree *T, struct rbtree_node *z){
// 无子节点时,删除节点可能为红色或者黑色;
// 1.1 如果为红色,直接删除即可,不会影响黑色节点的数量;
// 1.2 如果为黑色,则需要进行删除平衡的操作了;主要是这个!!!
// 2.只有一个子节点时,删除节点只能是黑色,其子节点为红色,否则无法满足红黑树的性质了。 此时用删除节点的子节点接到父节点,且将子节点颜色涂黑,保证黑色数量。
// 3.有两个子节点时,与二叉搜索树一样,使用后继节点作为替换的删除节点,情形转至为1或2处理。
// 当删除节点是黑色
// 1. 当前结点的兄弟结点是红色的-->兄弟变黑,父母变红,以父母为中心,旋转,自己然后变成原父母的兄弟结点
// 2. 当前结点的兄弟结点是黑色的,而且兄弟结点的,两个孩子结点都是黑色的-->兄弟变红,自己变成父母结点
// 3. 当前结点的兄弟结点是黑色的,而且兄弟结点的,左孩子是红色的-->兄弟变红,左子树变黑,兄弟右旋,变成下面情况
// 4. 当前结点的兄弟结点是黑色的,而且兄弟结点的,右孩子是红色的
struct rbtree_node *x = T->nil;//x代替y的位置
struct rbtree_node *y = T->nil;//替换节点
if(z->rbt.left == T->nil || z->rbt.right == T->nil){
y = z;
}else{
y = rbtree_mini(T,z->rbt.right);
}
if(y->rbt.left != T->nil){
x = y->rbt.left;
}else if(y->rbt.right != T->nil){
x = y->rbt.right;
}
x->rbt.parent = y->rbt.parent;
if(y->rbt.parent == T->nil){
T->root = x;
}else if(y == y->rbt.parent->rbt.left){
y->rbt.parent->rbt.left = x;
}else{
y->rbt.parent->rbt.right = x;
}
if(y != z){
z->key = y->key;
}
if(y->rbt.color == BLACK){
rbtree_delete_fixup(T,x);
}
T->nil->rbt.parent = T->nil;
return y;
}
struct rbtree_node *rbtree_search(rbtree *T, KEY_VALUE key) {
struct rbtree_node *node = T->root;
while (node != T->nil) {
if (key < node->key) {
node = node->rbt.left;
} else if (key > node->key) {
node = node->rbt.right;
} else {
return node;
}
}
return T->nil;
}
void rbtree_traversal(rbtree *T, struct rbtree_node *node,int deep){
if(node != T->nil){
rbtree_traversal(T,node->rbt.left,deep+1);
printf("key:%d, color:%d, deep=%d\n",node->key,node->rbt.color,deep);
rbtree_traversal(T,node->rbt.right,deep+1);
}
}
int main(){
rbtree* T = rbtree_create();
rbtree_insert(T,10);
rbtree_insert(T,20);
rbtree_insert(T,30);
rbtree_insert(T,40);
rbtree_insert(T,50);
rbtree_insert(T,60);
rbtree_insert(T,25);
rbtree_insert(T,35);
rbtree_traversal(T,T->root,1);
printf("\n");
struct rbtree_node *x = rbtree_search(T,10);
x = rbtree_delete(T,x);
free(x);
rbtree_traversal(T,T->root,1);
}
应用场景:
1、Linux内核中的进程调度
2、Linux内核中的进程虚拟内存
3、nginx
nginx的红黑树定义在
src/core/ngx_rbtree.h,src/core/ngx_rbtree.c
nginx的定时器模块用到了红黑树,src/event/ngx_event_timer.h,src/event/ngx_event_timer.c
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#ifndef _NGX_EVENT_TIMER_H_INCLUDED_
#define _NGX_EVENT_TIMER_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#define NGX_TIMER_INFINITE (ngx_msec_t) -1
#define NGX_TIMER_LAZY_DELAY 300
ngx_int_t ngx_event_timer_init(ngx_log_t *log);
ngx_msec_t ngx_event_find_timer(void);
void ngx_event_expire_timers(void);
ngx_int_t ngx_event_no_timers_left(void);
extern ngx_rbtree_t ngx_event_timer_rbtree;
static ngx_inline void
ngx_event_del_timer(ngx_event_t *ev)
{
//...
}
static ngx_inline void
ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
{
//...
}
#endif /* _NGX_EVENT_TIMER_H_INCLUDED_ */
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
ngx_rbtree_t ngx_event_timer_rbtree;
static ngx_rbtree_node_t ngx_event_timer_sentinel;
/*
* the event timer rbtree may contain the duplicate keys, however,
* it should not be a problem, because we use the rbtree to find
* a minimum timer value only
*/
ngx_int_t
ngx_event_timer_init(ngx_log_t *log)
{
//...
}
ngx_msec_t
ngx_event_find_timer(void)
{
//...
}
void
ngx_event_expire_timers(void)
{
//...
}
ngx_int_t
ngx_event_no_timers_left(void)
{
//...
}
ngx_event_t定义在src/event/ngx_event.h
struct ngx_event_s {
void *data;
unsigned write:1;
unsigned accept:1;
/* used to detect the stale events in kqueue and epoll */
unsigned instance:1;
/*
* the event was passed or would be passed to a kernel;
* in aio mode - operation was posted.
*/
unsigned active:1;
unsigned disabled:1;
/* the ready event; in aio mode 0 means that no operation can be posted */
unsigned ready:1;
unsigned oneshot:1;
/* aio operation is complete */
unsigned complete:1;
unsigned eof:1;
unsigned error:1;
unsigned timedout:1;
unsigned timer_set:1;
unsigned delayed:1;
unsigned deferred_accept:1;
/* the pending eof reported by kqueue, epoll or in aio chain operation */
unsigned pending_eof:1;
unsigned posted:1;
unsigned closed:1;
/* to test on worker exit */
unsigned channel:1;
unsigned resolver:1;
unsigned cancelable:1;
#if (NGX_HAVE_KQUEUE)
unsigned kq_vnode:1;
/* the pending errno reported by kqueue */
int kq_errno;
#endif
/*
* kqueue only:
* accept: number of sockets that wait to be accepted
* read: bytes to read when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag
* write: available space in buffer when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag
*
* iocp: TODO
*
* otherwise:
* accept: 1 if accept many, 0 otherwise
* read: bytes to read when event is ready, -1 if not known
*/
int available;
ngx_event_handler_pt handler;
#if (NGX_HAVE_IOCP)
ngx_event_ovlp_t ovlp;
#endif
ngx_uint_t index;
ngx_log_t *log;
ngx_rbtree_node_t timer;
/* the posted queue */
ngx_queue_t queue;
#if 0
/* the threads support */
/*
* the event thread context, we store it here
* if $(CC) does not understand __thread declaration
* and pthread_getspecific() is too costly
*/
void *thr_ctx;
#if (NGX_EVENT_T_PADDING)
/* event should not cross cache line in SMP */
uint32_t padding[NGX_EVENT_T_PADDING];
#endif
#endif
};
定义一个ngx_event_timer_rbtree的全局树根;
通过ngx_event_add_timer添加树节点,ngx_event_add_timer会判断未来时间戳(未来时间戳-原时间戳的时间间隔小于NGX_TIMER_LAZY_DELAY,则不加入);
通过ngx_event_find_timer查找最小时间戳(最左子树),到期返回0,未到期则返回时间差;
通过ngx_event_expire_timers,找到到期的树节点(最左子树),并调用回调函数;
//...
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
//...
ev->handler(ev);
//...
通过ngx_event_no_timers_left,判断树节点是否都是cancelable,都是cancelable则NGX_OK,否则NGX_AGAIN。
4、epoll