怎么才能弄明白红黑树

        红黑树本身就是一课二叉查找树,就是多加了两个要求

                1.树中的每个节点增加了一个存储颜色的标志域

                2.树中没有任何一条路径比其他路径长两倍,整棵树接近平衡状态

        所以它的结构体:

                

typedef enum {RED,BLACK}ColorType;
typedef struct RB_TREE{
    int key;
    struct RB_TREE* left;
    struct RB_TREE* right;
    struct RB_TREE* p;
    ColorType color;
}RB_TREE;

typedef struct RBT_Root{
    RB_TREE* root;
    RB_TREE* nil;
}RBT_Root;

               二叉树的五条性质:

                        1.根节点的颜色是黑色的

                        2.树中的节点颜色不是黑色就是红色

                        3.如果当前节点颜色是红色,那么他的两个孩子节点全是黑色

                        4.所有的叶子节点nil是黑色的

                        5.从根节点到任一叶子结点的路径包含相同数目的黑节点

        当进行红黑树的插入或者删除操作时,会破坏红黑树的这五条性质,所以需要对树进行调整

                        1.调整树中某些节点的指针结构

                        2.调整树中某些节点的颜色

              左旋:

                         将要左旋节点的父节点变成该节点的左子节点,如果旋转节点的右子树上有节点的话,将他变成父节点的右子节点。

void LeftRotate(RB_Root* T,RB_TREE* node) //T是根节点,node是要旋转的节点的父节点
{
    RB_TREE* tmp = node->right; 
    node->right = tmp->left; 
    if(node->right != T->nil) 
    {
        node->right->p = node;
    }
    tmp->p = node->p;
    if(tmp->p == T->nil)
    {
        T->root = tmp;
    }
    else if(tmp->key < tmp->p->key)
    {
        tmp->p->left = tmp;
    }
    else
    {
        tmp->p->right = tmp
    }

    tmp->left = node;
    node->p = tmp;
    
}

    右旋:

                将右旋结点的父节点连接到右旋节点的右子节点,如果右旋节点的右子树不为空,则将它连接到父节点的左子树上。

void RightRotate(RB_Root* T, RB_TREE* node) //T是根节点,node是要旋转节点的父节点
{
    RB_TREE* tmp = node->left; //找到父节点的左子节点,就是要旋转的节点
    node->left = tmp->right;
    if(node->left != T->nil)
    {
        node->left->p = node;
    }
    
    tmp->p = node->p;
    if(tmp->p == T->nil)
    {
        T->root = p;
    }
    else if(tmp->key < tmp->p->key)
    {
        tmp->p->left = tmp;
    }
    else
    {
        tmp->p->right = tmp;
    }
    tmp->right = node
    node->p = tmp;
}

红黑树插入新节点:

        1.找到新插入结点的位置

        2.将插入节点初始化,颜色设置成红,因为设置成红色不会破坏节点的黑色相等的那条性质

        3.但是插入红色时候如果父节点是红色的话,又破坏了红黑树的性质,这时候就要左旋右旋了,可以分为以下三种情况:

                1)插入位置为树根,只需要将节点颜色变为黑就行

                2)插入节点的双亲节点是黑色,那么再插个红的不会破坏红黑树的性质

                3)插入结点的双亲节点颜色是红色,那么再插个红的进去会破坏平衡,这时候就要根据父亲节点和叔叔结点的颜色进行判断:

                   父节点红色、叔叔节点也是红色,将他俩都变成黑色,将祖父节点变成红色,然后再把祖父节点变成当前节点,往上看看上层结构有没有被破坏。

                   父节点红色、叔叔节点黑色,且当前节点是父节点的右孩子,将父节点作为当前节点左旋。左旋后,将父节点的颜色变成黑色,祖父节点的颜色变为红色,再以祖父节点为当前节点右旋。

void InsertNode(RB_Root* T, RB_TREE* node) //T为根节点,node是要插入的节点
{
    while(node->p->Color == RED) //判断父节点是不是红色
    {
        if(node->p == node->p->p->left)
        {
            RB_TREE* uncle = node->p->->right //叔叔节点
            if(uncle->Color == RED)
            {
                node->p->Color = BLACK;
                uncle->Color = BLACK;
                uncle->p->Color = RED;
                node = node->p->p;
            }
            else //叔叔节点为黑色
            {
                 if(node == node->p->right)
                 {
                    node = node->p;
                    LeftRorate(T,node);
                 }              
                 else
                 {
                    node->p->color = BLOCK;
                    node->p->p->Color = RED;
                    RightRorate(T,node->p->p);
                 } 
            }
        }
        else //父节点是祖父节点的右孩子
        {
            RB_TREE *uncle = node->p->p->left;
            if(uncle->Color == RED)
            {
                node->p->p->Color = RED;
                node->p->Color = BLACK;
                uncle->Color = BLACK;
                node = node->p->p;
            }
            else
            {
                if(node == node->p->left)
                {
                    node = node->p;
                    RightRorate(T,node);
                }
                else
                {
                    node->p->Color = BLACK;
                    node->p->p->Color = RED;
                    LeftRorate(T,node->p->p);
                }
            }
        }
    }
    T->Root->Colot = BLACK;
}

voif Insert(RB_Root** T,int key)
{
    RB_TREE* tmp,p;
    tmp = (*T)->root;
    p = tmp;
    while(tmp != (*T)->nil)
    {
        p = tmp;
        if(key < tmp->key)
        {
            tmp = tmp->left;
        }
        else if(key > tmp->key)
        {
            tmp = tmp->right;
        }
        else
        {
            printf("key is exist\n");
            return;
        }
    }

    tmp = (RB_TREE *)malloc(sizeof(RB_TREE));
    tmp->key = key;
    tmp->Color = RED;
    tmp->left = tmp->right = (*T)->nil;
    tmp->p = p;

    if((*T)->root == (*T)->nil)
    {
        (*T)->roor = tmp;
    }
    else if(key < p->key)
    {
        p-left = tmp;
    }
    else
    {
        p->right = tmp;
    }
    InsertNode((*T),tmp);

}

红黑树删除节点:

        1.查找到要删除的节点,先删除

                1)删除的节点本身就是叶子节点,直接删除

                2)只有一个孩子节点,让孩子节点顶替

                3)有两个孩子节点,找到该节点右子树中值最小的叶子节点来顶替该节点,并把值最小的叶子节点删除

        2.重新调整红黑树的平衡

                1)如果删除的节点是红色,不会破坏树的平衡

                2)如果删除节点是黑色,分四种情况:

                        删除节点的兄弟节点是红色:将兄弟节点变成黑色,父节点变成红色,以父节点进行左旋,更新删除节点的兄弟节点。

                        删除节点的兄弟节点是黑色,左孩子是红色,右孩子是黑色:将兄弟节点变成红色,兄弟节点的左孩子变成黑色,以兄弟节点进行右旋操作

                        删除节点的兴地节点及孩子节点全部都是黑色:将删除节点的兄弟节点设置成红色,将删除节点的父节点设置成当前节点继续判断。

                        删除节点的兄弟节点是黑色,右孩子是红色:将删除节点的父节点的颜色赋值给兄弟节点,设置父节点的颜色为黑色,兄弟节点右孩子黑色,再根据父节点左旋。

RB_TREE* FindMin(RB_Root* T,RB_TREE* t)
{
    if(t== T->nil)
    {
        return T->nil;
    }
    while(t->left != T->nil)
    {
        t = t->left;
    }
    return t;
}

void Transplant(RB_Root* T,RB_TREE* u,RB_TREE* v)
{
    if(u->p == T->nil)
    {
        T->root = v;
    }
    else if(u == u->p->left)
    {
        u->p->left = v;
    }
    else
    {
        u->p->right = v;
    }
    v->p = u->p;
}

void DeleteFixup(RB_Root** T,RB_TREE* x)
{
    while(x != (*T)->root && x->Color == BLACK)
    {
        if(x == x->p->left)
        {
            RB_TREE* w = x->p->right;
            if(RED == w->Color)
            {
                w->Color = BLACK;
                w->p->Color = RED;
                LeftRorate((*T),x->p);
                w = x->p->right;
            }
            if(BLACK == w->left->Color && w->right->Color = BLACK)
            {
                    w->Color = RED;
                    x = x->p;
            }
            if(w->left->Color == RED && w->right->Color == BLACK)
            {
                w->left->Color = BLACK;
                w->Color = RED;
                RightRorate((*T),w);
                w = x->p->right;
            }
            if(w->right->Color == RED)
            {
                w->Color = x->p->Color;
                x->p->Color = BLACK;
                x->right->Color = BLACK;
                LeftRorate((*T),x->p);
                x = (*T)->root;
            }
            
        }
        else
        {
            RB_TREE* w = x->p->left;
            if(RED == w->Color)
            {
                w->Color = BLACK;
                w->p->Color = RED;
                RightRorate((*T),x->p);
                w = x->p->left;
            }
            if(BLACK == w->left->Color && w->right->Color = BLACK)
            {
                    w->Color = RED;
                    x = x->p;
            }
            if(w->left->Color == BLACK && w->right->Color == RED)
            {
                w->right->Color = BLACK;
                w->Color = RED;
                RightRorate((*T),w);
                w = x->p->left;
            }
            if(w->right->Color == BLACK)
            {
                w->Color = x->p->Color;
                x->p->Color = BLACK;
                x->left->Color = BLACK;
                LeftRorate((*T),x->p);
                x = (*T)->root;
            }
        }
    }
    x->Color = BLACK;
}

void Delete(RB_Root* T,int key)
{
    if(NULL == (*T)->root)
    {
        return;
    }

    RB_TREE* todelete = (*T)->root;
    RB_TREE* x = NULL;
    while(todelete != (*T)->nil && todelete->key != key)
    {
        if(key < todelete->key)
        {
            todelete = todelete->left;
        }
        else if(key > todelete->key)
        {
            todelete = todelete->right;
        }
       
    }
    if(todelete == (*T)->nil)
    {
        printf("key not exist\n");
        return;
    }
    if(todelete->left != (*T)->nil && todelete->right != (*T)->nil)
    {
        RB_TREE* alternative = findMin((*T),todelete->right);
        key = todelete->key = alternative->key;
        todelete = alternative;
    }
    if(todelete->left == (*T)->nil)
    {
        x = todelete->right;
        Transplant((*T),todelete,todelete->right);
    }
    else if(todelete->right == (*T)->nil)
    {
        x = todelete->left;
        Transplant((*T),todelete,todelete->left);
    }
    if(todelete->Color == BLACK)
    {
        DeleteFixup(T,x);
    }
    free(todelete);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值