nginx红黑树

插入
向红黑树中插入节点,有可能破坏红黑树的性质,这时就需要调整红黑树,哪些情况会破坏红黑树的性质呢?下面三种情况会破坏红黑树的性质:
1)如果当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色
2)当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
3)当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子
下面是这三种情况的对应调整方法(这里只是父节点为祖父节点的左孩子(右孩子情况类同)):
如果当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色 ,调整方法如下:
1)将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点,从新的当前节点重新开始算法
如果当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子, 调整方法如下:
2)当前节点的父节点做为新的当前节点,以新当前节点为支点左旋
如果当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子 ,调整方法如下:
3)父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋
void
ngx_rbtree_insert(ngx_thread_volatile ngx_rbtree_t *tree,
    ngx_rbtree_node_t *node)
{
    ngx_rbtree_node_t  **root, *temp, *sentinel;

    /* a binary tree insert */

    root = (ngx_rbtree_node_t **) &tree->root;
    sentinel = tree->sentinel;//哨兵节点

    if (*root == sentinel) {//如果根节点为空
        node->parent = NULL;
        node->left = sentinel;
        node->right = sentinel;
        ngx_rbt_black(node);//根节点设置为黑色
        *root = node;

        return;
    }

    tree->insert(*root, node, sentinel);//插入节点

    /* re-balance tree */  /*插入调整*/

    while (node != *root && ngx_rbt_is_red(node->parent)) {//当前节点不是根节点,并且节点的父节点颜色为红色
        //父节点为祖父节点的左孩子
        if (node->parent == node->parent->parent->left) {
            temp = node->parent->parent->right;//取叔叔节点
            //情况1:父节点为红,叔叔节点为红
            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 {//情况2:父节点为红,叔叔节点为黑色,当前节点为父节点的右孩子
                if (node == node->parent->right) {//解决方法:
                    node = node->parent;//修改当前节点为父节点
                    ngx_rbtree_left_rotate(root, sentinel, node);//左旋当前节点
                }
                //情况3:父节点为红,叔叔节点为黑色,当前节点为父节点的左孩子
                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);//根节点永远是黑色
}

删除
 在红黑树中删除节点,删除节点也有可能破坏红黑树的性质,需要调整红黑树。下面四种删除操作会破坏红黑树的性质:
1)当前节点是黑+黑且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)
2)当前节点是黑加黑且兄弟是黑色且兄弟节点的两个子节点全为黑色
3)当前节点颜色是黑+黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色
4)当前节点颜色是黑-黑色,它的兄弟节点是黑色,但是兄弟节点的右子是红色,兄弟节点左子的颜色任意
下面是这四种情况对应的调整方法:
如果当前节点是黑+黑且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑),调整如下:
1)把父节点染成红色,把兄弟结点染成黑色,左旋父节点
如果 当前节点是黑加黑且兄弟是黑色且兄弟节点的两个子节点全为黑色 ,调整如下:
2)把当前节点和兄弟节点中抽取一重黑色追加到父节点上,把父节点当成新的当前节点
如果 当前节点颜色是黑+黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色 ,调整如下:
3)把兄弟结点染红,兄弟左子节点染黑,之后再在兄弟节点为支点解右旋
如果 当前节点颜色是黑-黑色,它的兄弟节点是黑色,但是兄弟节点的右子是红色,兄弟节点左子的颜色任意 ,调整如下:
4)把兄弟节点染成当前节点父节点的颜色,把当前节点父节点染成黑色,兄弟节点右子染成黑色,之后以当前节点的父节点为支点进行左旋。
void
ngx_rbtree_delete(ngx_thread_volatile ngx_rbtree_t *tree,
    ngx_rbtree_node_t *node)
{
    ngx_uint_t           red;
    ngx_rbtree_node_t  **root, *sentinel, *subst, *temp, *w;

    /* a binary tree delete */

    root = (ngx_rbtree_node_t **) &tree->root;
    sentinel = tree->sentinel;//哨兵节点

    if (node->left == sentinel) {//左子节点为空
        temp = node->right;
        subst = node;//subst记录后继节点,用着个节点代替删除节点

    } 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);

        /* DEBUG stuff */
        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;
    }

    if (subst == node) {

        temp->parent = subst->parent;

    } else {

        if (subst->parent == node) {
            temp->parent = subst;

        } else {
            temp->parent = subst->parent;
        }

        subst->left = node->left;
        subst->right = node->right;
        subst->parent = node->parent;
        ngx_rbt_copy_color(subst, node);

        if (node == *root) {
            *root = subst;

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

        if (subst->left != sentinel) {
            subst->left->parent = subst;
        }

        if (subst->right != sentinel) {
            subst->right->parent = subst;
        }
    }

    /* DEBUG stuff */
    node->left = NULL;
    node->right = NULL;
    node->parent = NULL;
    node->key = 0;

    if (red) {//
        return;
    }

    /* a delete fixup *///调整红黑树的四种情况,看注释

    while (temp != *root && ngx_rbt_is_black(temp)) {
        //当前节点为左节点的情况
        if (temp == temp->parent->left) {
            w = temp->parent->right;
            //情况1:当前节点为黑色,兄弟节点为红色
            if (ngx_rbt_is_red(w)) {
                ngx_rbt_black(w);//解决: 兄弟节点修改为黑色
                ngx_rbt_red(temp->parent);//父节点修改红色
                ngx_rbtree_left_rotate(root, sentinel, temp->parent);//左旋父节点
                w = temp->parent->right;
            }
            //情况2:当前节点为黑色,兄弟节点为黑色,兄弟节点的俩子节点也为黑色
            if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
                ngx_rbt_red(w);//解决:兄弟节点修改为红色
                temp = temp->parent;//当前节点指向父节点

            } else {//情况3:当前节点为黑色,兄弟节点为黑色,兄弟节点右子节点为黑色,左子节点为红色
                if (ngx_rbt_is_black(w->right)) {
                    ngx_rbt_black(w->left);//解决:左子节点改为黑色
                    ngx_rbt_red(w);//兄弟节点改为红色
                    ngx_rbtree_right_rotate(root, sentinel, w);//右旋兄弟节点
                    w = temp->parent->right;
                }
                //情况4:当前节点为黑色,兄弟节点为黑色,兄弟节点右子节点为红色,左子节点任意色
                ngx_rbt_copy_color(w, temp->parent);//解决:兄弟节点修改为父节点的颜色
                ngx_rbt_black(temp->parent);        //父节点修给为黑色
                ngx_rbt_black(w->right);            //右子节点修改为黑色
                ngx_rbtree_left_rotate(root, sentinel, temp->parent);//左旋父节点
                temp = *root;
            }

        } else {//当前节点为右节点的情况
            w = temp->parent->left;

            if (ngx_rbt_is_red(w)) {
                ngx_rbt_black(w);
                ngx_rbt_red(temp->parent);
                ngx_rbtree_right_rotate(root, sentinel, temp->parent);
                w = temp->parent->left;
            }

            if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
                ngx_rbt_red(w);
                temp = temp->parent;

            } else {
                if (ngx_rbt_is_black(w->left)) {
                    ngx_rbt_black(w->right);
                    ngx_rbt_red(w);
                    ngx_rbtree_left_rotate(root, sentinel, w);
                    w = temp->parent->left;
                }

                ngx_rbt_copy_color(w, temp->parent);
                ngx_rbt_black(temp->parent);
                ngx_rbt_black(w->left);
                ngx_rbtree_right_rotate(root, sentinel, temp->parent);
                temp = *root;
            }
        }
    }

    ngx_rbt_black(temp);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值