Nginx红黑树分析

红黑树的五个特性如下:

  1. 红黑树是一棵平衡二叉树
  2. 每个节点非红即黑
  3. 根节点是黑色
  4. 红节点的子节点必为黑色
  5. 任一节点到其各个叶子节点所经过的黑色节点是相等的

nginx中的红黑树数据结构如下:

struct ngx_rbtree_s{
    ngx_rbtree_node_t *root;//根节点指针
    ngx_rbtree_node_t *sentinel;//叶子节点
    ngx_rbtree_insert_pt insert;//插入方法
};// 这是红黑树的结构
struct ngx_rbtree_node_s{
    ngx_rbtree_key_t       key;     /* 节点的键值 */
    ngx_rbtree_node_t     *left;    /* 节点的左孩子 */
    ngx_rbtree_node_t     *right;   /* 节点的右孩子 */
    ngx_rbtree_node_t     *parent;  /* 节点的父亲 */
    u_char                 color;   /* 节点的颜色 */
    u_char                 data;  
};

 红黑树的插入通常会以平衡二叉树的方式先插入,然后再对节点造成的不平衡进行处理.

void
ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
{
    ngx_rbtree_node_t  **root, *temp, *sentinel;
    root = (ngx_rbtree_node_t **) &tree->root;
    sentinel = tree->sentinel;
    
    if(*root == sentinel){//情况1,空树插入节点,只将节点染成黑色即可
        node->parent = NULL;
        node->left = sentinel;
        node->right = sentinel;
        ngx_rbt_black(node);
        *root = node;//将树的根指向新节点
        return;
    }
    
    tree->insert(*root, sentinel, node);//调用自定义的插入节点方法
    
    /*新插入的节点为红色,如果父节点也是红色,则平衡被破坏,需要处理*/
    while(node != *root && ngx_rbt_is_red(node->parent)){
        //先考虑新增节点的父节点是祖父节点左子树的情况
        if(node->parent == node->parent->parent->left){
            temp = node->parent->parent->right;//树父节点
            if(ngx_rbt_is_red(temp)){
            /*如果叔父节点是红色,说明叔父节点与父节点的平衡因子差1,
原则上符合avl树的平衡规则,则
将父节点和叔父节点都染成黑色,将祖父节点染红,此时祖父节点破坏了红黑树的平衡,
再以祖父节点进行平衡处理*/
                ngx_rbt_black(node->parent);
                ngx_rbt_black(temp);
                ngx_rbt_red(node->parent->parent);
                node = node->parent->parent;
            }else{
                if(node == node->parent->right){
                   /*如果插入节点是一个右节点,先对父节点进行左旋处理*/
                    node = node->parent;
                    ngx_rbtree_left_rotate(root, sentinel, node);
                }
                //如果叔父节点是黑色或者是一个叶子,则说明父节点和叔父节点的平衡因子大于1,
//失去平衡,则需要对祖父节点进行右旋,先将父节点染黑,将祖父节点染红,对祖父节点右旋
                ngx_rbt_black(node->parent);
                ngx_rbt_red(node->parent->parent);
                ngx_rbtree_right_rotate(root, sentinel, node->parent->parent);
            }
        }else{
        //以下与上面是对称的,
            temp = node->parent->parent->left;
            if (ngx_rbt_is_red(temp)) {
                ngx_rbt_black(node->parent);
                ngx_rbt_black(temp);
                ngx_rbt_red(node->parent->parent);
                node = node->parent->parent;

            } else {
                if (node == node->parent->left) {
                    node = node->parent;
                    ngx_rbtree_right_rotate(root, sentinel, node);
                }

                ngx_rbt_black(node->parent);
                ngx_rbt_red(node->parent->parent);
                ngx_rbtree_left_rotate(root, sentinel, node->parent->parent);
            }
        }
    }
    ngx_rbt_black(*root);
}

平衡树的左旋操作:

将当前节点的右节点作为当前节点的父节点,将当前节点右节点的左节点作为当前节点的右节点;

static ngx_inline void
ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    ngx_rbtree_node_t *node){

    ngx_rbtree_node_t  *temp;
    temp = node->right;//先定位到右节点
    node->right = temp->left;//将右节点的左节点赋给当前节点的右节点

    if(temp->left != sentinel){//如果被移动的节点不是一个叶子,则需要将父指针赋值
        temp->left->parent = node;
    }
    temp->parent = node->parent;//改变右节点的父指针

    if(node == *root){//如果是对根进行左旋,则需要修改根指针
        *root = temp;
    }else if (node == node->parent->left) {//对父级节点的左右指针进行修改
        node->parent->left = temp;

    } else {
        node->parent->right = temp;
    }

    temp->left = node;//最后将当前节点赋给其右节点的左节点,完成左旋
    node->parent = temp;//修改父指针指向
}

平衡树的右旋操作:

 右旋是将当前节点的左节点的右节点赋给当前节点的右节点,将当前节点赋给当前节点左节点的右节点.

static ngx_inline void
ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    ngx_rbtree_node_t *node){
    ngx_rbtree_node_t  *temp;

    temp = node->left;//先定位左节点
    node->left = temp->right;//将左节点的右节点赋给当前节点的左节点

    if(temp->right != sentinel){
        temp->right->parent = node;
    }
    temp->parent = node->parent;//修改左节点的父指针

    /*修改祖父节点的左指针或右指针*/
    if (node == *root) {
        *root = temp;

    } else if (node == node->parent->right) {
        node->parent->right = temp;

    } else {
        node->parent->left = temp;
    }

    temp->right = node;//最后将当前节点赋给其左节点的右节点
    node->parent = temp;//修改当前节点的父节点为其左节点,旋转完成
}

红黑树的删除:

void
ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
{
    ngx_uint_t red;
    ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w;
    
    root = (ngx_rbtree_node_t **)&tree->root;
    sentinel = tree->sentinel;

    if(node->left == sentinel){
        temp = node->right;
        subst = node;
    } else if (node->right == sentinel) {
        temp = node->left;
        subst = node;

    } else{
        subst = ngx_rbtree_min(node->right, sentinel);
        if(subst->left != sentinel){
            temp = subst->left;
        }else{
            temp = subst->right;
        }
    }
    
    if(subst == *root){
        *root = temp;
        ngx_rbt_black(temp);
        node->left = NULL;
        node->right = NULL;
        node->parent = NULL;
        node->key = 0;
        return;
    }
    
    red =  ngx_rbt_is_red(subst);
    if(subst == subst->parent->left){
        subst->parent->left = temp;
    }else{
        subst->parent->right = temp;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值