现在的位置: 首页 > 综合 > 正文

红黑树

2018年02月21日 ⁄ 综合 ⁄ 共 4275字 ⁄ 字号 评论关闭

红黑树:

enum nodecolor {red,black};
struct red_black_node
{
    int key;
    red_black_node *left;
    red_black_node *right;
    red_black_node *p;
    nodecolor color;
    red_black_node(int a,nodecolor c=red)
    {
        key=a;
        color=c;
    }
};

static red_black_node *NIL=new red_black_node(0,black);

red_black_node* tree_minimum(red_black_node *x)
{
    while(x->left!=NIL)
        x=x->left;
    return x;
}

red_black_node* tree_successor(red_black_node *x)
//寻找后继结点,没有则返回NIL,O(h)
{
    if(x->right!=NIL)//如果x的右子树非空,后继即右子树的最左结点
        return tree_minimum(x->right);
    red_black_node* y=x->p;
    //如果x的右子树为空,向上查找,直到遇到某个是其父结点的左儿子的结点为止
    while(y!=NIL && x==y->right)
    {
        x=y;
        y=y->p;
    }
    return y;
}

red_black_node* left_rotate(red_black_node *t,red_black_node *x)
//左旋,根为t,旋转结点为x,y为x的右儿子,返回旋转之后的根,O(1)
{
    red_black_node *root=t;
    red_black_node *y=x->right;
    x->right=y->left;
    if(y->left!=NIL)
        y->left->p=x;
    y->p=x->p;
    if(x->p==NIL)//x是根的情况
        root=y;
    else if(x==x->p->left)
        x->p->left=y;
    else
        x->p->right=y;
    y->left=x;
    x->p=y;
    return root;
}

red_black_node* right_rotate(red_black_node *t,red_black_node *x)
//右旋,根为t,旋转结点为x,y为x的左儿子,返回旋转之后的根,O(1)
{
    red_black_node *root=t;
    red_black_node *y=x->left;
    x->left=y->right;
    if(y->right!=NIL)
        y->right->p=x;
    y->p=x->p;
    if(x->p==NIL)//x是根的情况
        root=y;
    else if(x==x->p->left)
        x->p->left=y;
    else
        x->p->right=y;
    y->right=x;
    x->p=y;
    return root;
}

red_black_node* rb_insert_fixup(red_black_node *x,red_black_node *z)
//在插入z后,调用该函数来保持红黑性质,x为根,z为插入的结点,返回根结点,O(lgn),最多旋转2次
{
    red_black_node *y;
    while(z->p->color==red)//z和z的父结点都为红色时才需要调整
    {
        if(z->p==z->p->p->left)
        {
            y=z->p->p->right;//y是z的叔叔结点,根据y的颜色分成3种情况
            if(y->color==red)//情况1,y为红色
            {
                z->p->color=black;
                y->color=black;//将父结点和叔叔结点都着黑色以解决z和z的父结点都为红色
                z->p->p->color=red;//将祖父结点着红色以保持性质5
                z=z->p->p;//将z的祖父的父结点可能也是红色,将z置为其祖父再次循环
            }
            else//情况2和3,y为黑色
            {
                if(z->p->right==z)//情况2,y黑色且z是右孩子
                {
                    z=z->p;
                    x=left_rotate(x,z);//对z父亲使用一次左旋使之转变为情况3
                }
                //情况3,y黑色且z是左孩子
                z->p->color=black;
                z->p->p->color=red;
                right_rotate(x,z->p->p);//此时z的父结点为黑色,无需再执行while循环
            }
        }
        else//下面的跟上面一样,只要左右互换
        {
            y=z->p->p->left;
            if(y->color==red)
            {
                z->p->color=black;
                y->color=black;
                z->p->p->color=red;
                z=z->p->p;
            }
            else
            {
                if(z->p->left==z)
                {
                    z=z->p;
                    x=right_rotate(x,z);
                }
                z->p->color=black;
                z->p->p->color=red;
                left_rotate(x,z->p->p);
            }
        }
    }
    x->color=black;//最后记得把根着为黑色
    return x;
}

red_black_node* rb_insert(red_black_node *x,red_black_node *z)
//在根为x的红黑树中插入结点z,O(lgn),最多旋转2次
{
    red_black_node *y=NIL;
    red_black_node *root=x;
    while(x!=NIL)
    {
        y=x;
        if(z->key<x->key)
            x=x->left;
        else
            x=x->right;
    }
    z->p=y;
    if(y==NIL)
        root=z;
    else if(z->key<y->key)
        y->left=z;
    else
        y->right=z;
    z->left=NIL;
    z->right=NIL;
    z->color=red;//要将z的孩子置为NIL并着为红色
    x=root;
    x=rb_insert_fixup(x,z);//保持红黑性质
    return x;
}

red_black_node* rb_delete_fixup(red_black_node *x,red_black_node *q)
//删除黑色结点后恢复红黑性质,x为根,q为删除结点y的唯一孩子或者为NIL,返回根结点,O(lgn),最多旋转3次
{
    red_black_node* w=NIL;
    while(q!=x && q->color==black)
    //while循环的目标是将额外的黑色沿树上移
    {
        if(q==q->p->left)
        {
            w=q->p->right;//w是q的兄弟,q为双重黑色,所以w不可能为NIL
            if(w->color==red)//情况1,w是红色
            {
                w->color=black;
                q->p->color=red;//改变w和q->p的颜色
                x=left_rotate(x,q->p);//对q->p进行左旋,红黑性质继续保持
                w=q->p->right;//w赋值为q的新兄弟,转到情况2,3,4
            }
            if(w->left->color==black && w->right->color==black)
            //情况2,w是黑色且w两个孩子都是黑色
            {
                w->color=red;
                q=q->p;
                //通过while循环不断上升,如遇到红色结点跳出循环,在函数最后q被着黑色
                //如果是通过情况1进入情况2,则q->p必为红色,直接循环结束
            }
            else//情况3,4
            {
                if(w->right->color==black)
                //情况3,w是黑色且w的孩子左红右黑
                {
                    w->left->color=black;
                    w->color=red;
                    x=right_rotate(x,w);
                    w=q->p->right;
                    //交换w和其左孩子颜色并对w右旋,转情况4
                }
                //情况4,w是黑色且右孩子是红色
                w->color=q->p->color;
                q->p->color=black;
                w->right->color=black;
                x=left_rotate(x,q->p);
                //去掉q额外的黑色
                q=x;//q置为根,循环结束
            }

        }
        else
        {
            w=q->p->left;
            if(w->color==red)
            {
                w->color=black;
                q->p->color=red;
                x=right_rotate(x,q->p);
                w=q->p->left;
            }
            if(w->left->color==black && w->right->color==black)
            {
                w->color=red;
                q=q->p;
            }
            else if(w->left->color==black)
            {
                w->right->color=black;
                w->color=red;
                x=left_rotate(x,w);
                w=q->p->left;
            }
            w->color=q->p->color;
            q->p->color=black;
            w->left->color=black;
            x=right_rotate(x,q->p);
            q=x;
        }
    }
    q->color=black;
    return x;
}

red_black_node* rb_delete(red_black_node *x,red_black_node *z)
//在根为x的红黑树中删除结点z,O(lgn),最多旋转3次
{
    red_black_node *y=NIL;
    red_black_node *q=NIL;
    red_black_node *root=x;
    if(z->left==NIL||z->right==NIL)
        y=z;
    else
        y=tree_successor(z);
    if (y->left!=NIL)
        q=y->left;
    else
        q=y->right;
    q->p=y->p;//无条件赋值
    if(y->p==NIL)
        root=q;
    else if(y==y->p->left)
        y->p->left=q;
    else
        y->p->right=q;
    if(y!=z)
        z->key=y->key;
    x=root;
    if(y->color==black)//删除的是黑色结点才调用
        x=rb_delete_fixup(x,q);//q是y的唯一孩子或者是哨兵NIL
    return x;
}

void inorder_walk(red_black_node *x)
{
    if(x!=NIL)
    {
        inorder_walk(x->left);
        if(x->color==red)
            cout<<"red";
        else
            cout<<"black";
        cout<<x->key<<" ";
        inorder_walk(x->right);
    }
}


【上篇】
【下篇】

抱歉!评论已关闭.