1.2 红黑树 学习笔记

参考: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

猜你喜欢

转载自blog.csdn.net/ZRXSLYG/article/details/112686446