手撕红黑树--增删改查


这里默认大家都知道红黑树的基本概念了,重点讲如何用代码实现(用的是c语言)
打卡机实战应用红黑树:
链接: https://github.com/furyParrot/ClockMachine_RBTree.

1节点定义

typedef struct Node
{
    int keyvalue;       //键值,一棵树中每个key都是唯一的,用来比较
    int Red1Black0;     //红黑,0黑 1红
    Content * cont;     //节点内容
    struct Node * lson; //指向左儿子的指针
    struct Node * rson; //指向右儿子的指针
    struct Node * dad;  //指向父节点的指针
} Node;

2增加节点

函数:int AddNode(Node* root, Node* newnode)
root:插入寻找的出发节点
newnode:需要插入的新节点

newnode的key大
黑色
红色
红色
黑色
newnode的key大
首个节点?
直接将newnode内容赋值给根节点
进行key比较
root是否有右子
将root->rson作为根节点递归插入newnode
root是黑色还是红色
直接插入
叔叔颜色
爸爸叔叔爷爷同时变色,爷爷作为新节点递归插入祖父
爸爸和我同向
同向旋转操作并变色-见下文
折拐旋转为同向-详见下文
root是否有左子
将root->lson作为根节点递归插入newnode

同向旋转操作并变色
1:左左:先旋转,然后root 以及 root->dad变色
在这里插入图片描述

2:右右:先旋转,然后root 以及 root->dad变色
在这里插入图片描述

不同向转为同向:
1左右–>变为同向情况并递归
在这里插入图片描述
2右左–>变为同向情况并递归
在这里插入图片描述

代码:

int AddNode(Node* root, Node* newnode) {
    //是首个节点
    if (root->keyvalue == 0) {
        //将值赋值给根节点。
        root->keyvalue = newnode->keyvalue;
        ContCpy(root->cont, newnode->cont);
        //free(newnode);
    }
    //不是
    else {
        if (newnode->keyvalue == root->keyvalue) {
            root->cont = newnode->cont;
        }
        else if (newnode->keyvalue > root->keyvalue) { //要往右边插

            if (root->rson != NULL) {//有右儿子的时候
                AddNode(root->rson, newnode);
            }
            else {//没右儿子的时候

                if (root->Red1Black0 == 0) { //爸是黑色,直接插入
                    root->rson = newnode;
                    newnode->dad = root;
                }
                else {  //爸是红色
                    int dadRight1Left0 = (root->dad->rson == NULL) ? 0 : ((root->keyvalue == root->dad->rson->keyvalue) ? 1 : 0);


                    if (((dadRight1Left0 == 1) && (root->dad->lson != NULL) && (root->dad->lson->Red1Black0 == 1)) ||
                        ((dadRight1Left0 == 0) && (root->dad->rson != NULL) && (root->dad->rson->Red1Black0 == 1))) {//叔叔是红色
                            //爸爸叔叔爷爷同时变色
                        root->Red1Black0 = 0;
                        if (dadRight1Left0 == 1) {
                            if (root->dad->lson != NULL)
                                root->dad->lson->Red1Black0 = 0;
                        }
                        else {
                            if (root->dad->rson != NULL)
                                root->dad->rson->Red1Black0 = 0;
                        }
                        root->dad->Red1Black0 = 1;
                        //将newnode插入
                        root->rson = newnode;
                        newnode->dad = root;
                        //爷爷变色,需要将爷爷插入祖父,如果没有祖父,就直接给爷爷变色
                        if (root->dad->dad == NULL) {
                            root->dad->Red1Black0 = 0;
                        }
                        else {
                            int ppRight1Left0 = (root->dad->dad->rson == NULL) ? 0 : ((root->dad->keyvalue == root->dad->dad->rson->keyvalue) ? 1 : 0);
                            if (ppRight1Left0 == 1) {
                                root->dad->dad->rson = NULL;
                                //root->dad->dad = NULL;
                            }
                            AddNode(root->dad->dad, root->dad);
                        }
                    }
                    else {//叔叔是黑色
                        if (dadRight1Left0 == 1) {//爸爸是爷爷的右儿子,和我同向:

                            Node* newpapa = CreatRBTree();
                            newpapa->keyvalue = root->dad->keyvalue;
                            ContCpy(newpapa->cont, root->dad->cont);

                            if (root->dad->lson != NULL) root->dad->lson->dad = newpapa;
                            newpapa->lson = root->dad->lson;

                            if (root->lson != NULL) root->lson->dad = newpapa;
                            newpapa->rson = root->lson;

                            root->dad->lson = newpapa;
                            newpapa->dad = root->dad;

                            root->dad->rson = newnode;
                            newnode->dad = root->dad;

                            root->dad->Red1Black0 = 0;
                            newpapa->Red1Black0 = 1;


                            root->dad->keyvalue = root->keyvalue;
                            ContCpy(root->dad->cont, root->cont);
                            //free(root);

                        }
                        else {//爸爸是爷爷的左儿子,和我反向:需要旋转操作
                            root->rson = newnode->lson;
                            if (newnode->lson != NULL) newnode->lson->dad = root;
                            newnode->lson = NULL;
                            root->dad->lson = newnode;
                            newnode->dad = root->dad;
                            root->dad = NULL;
                            AddNode(newnode, root);
                        }
                    }
                }
            }
        }
        else { //要往左边插
            if (root->lson != NULL) {//有左儿子的时候
                AddNode(root->lson, newnode);
            }
            else {//没左儿子的时候
                if (root->Red1Black0 == 0) { //爸是黑色,直接插入
                    root->lson = newnode;
                    newnode->dad = root;
                }
                else {  //爸是红色
                    int dadRight1Left0 = (root->dad->rson == NULL) ? 0 : ((root->keyvalue == root->dad->rson->keyvalue) ? 1 : 0);

                    if (((dadRight1Left0 == 1) && (root->dad->lson != NULL) && (root->dad->lson->Red1Black0 == 1)) ||
                        ((dadRight1Left0 == 0) && (root->dad->rson != NULL) && (root->dad->rson->Red1Black0 == 1))) { //叔叔是红色
                            //爸爸叔叔爷爷同时变色
                        root->Red1Black0 = 0;
                        if (dadRight1Left0 == 1) {
                            if (root->dad->lson != NULL)
                                root->dad->lson->Red1Black0 = 0;
                        }
                        else {
                            if (root->dad->rson != NULL)
                                root->dad->rson->Red1Black0 = 0;
                        }
                        root->dad->Red1Black0 = 1;
                        //将newnode插入
                        root->lson = newnode;
                        newnode->dad = root;
                        //爷爷变色,需要将爷爷插入祖父,如果没有祖父,就直接给爷爷变色
                        if (root->dad->dad == NULL) {
                            root->dad->Red1Black0 = 0;
                        }
                        else {
                            int ppRight1Left0 = (root->dad->dad->rson == NULL) ? 0 : ((root->dad->keyvalue == root->dad->dad->rson->keyvalue) ? 1 : 0);
                            if (ppRight1Left0 == 1) {
                                root->dad->dad->rson = NULL;
                                //root->dad->dad = NULL;
                            }
                            AddNode(root->dad->dad, root->dad);
                        }
                    }
                    else {//叔叔是黑色
                        if (dadRight1Left0 == 0) {//爸爸是爷爷的左儿子,和我同向:

                            Node* newpapa = CreatRBTree();
                            newpapa->keyvalue = root->dad->keyvalue;
                            ContCpy(newpapa->cont, root->dad->cont);
                            

                            if (root->dad->rson != NULL) root->dad->rson->dad = newpapa;
                            newpapa->rson = root->dad->rson;

                            if (root->rson != NULL) root->rson->dad = newpapa;
                            newpapa->lson = root->rson;

                            root->dad->rson = newpapa;
                            newpapa->dad = root->dad;

                            root->dad->lson = newnode;
                            newnode->dad = root->dad;

                            root->dad->Red1Black0 = 0;
                            newpapa->Red1Black0 = 1;

                            root->dad->keyvalue = root->keyvalue;
                            ContCpy(root->dad->cont , root->cont);
                            //free(root);
                        }
                        else {//爸爸是爷爷的右儿子,和我反向:需要旋转操作
                            root->lson = newnode->rson;
                            if (newnode->rson != NULL) newnode->rson->dad = root;
                            newnode->rson = NULL;
                            root->dad->rson = newnode;
                            newnode->dad = root->dad;
                            root->dad = NULL;
                            AddNode(newnode, root);
                        }
                    }
                }
            }
        }
    }
    return 1;
}

3删除节点

int RemoveNode(Node* node)

0
红色
黑色
1
2
node有几个子节点
node颜色
直接删除
需要删除平衡
子节点必红,直接取代node即可
用临近节点取代node,并递归删除临近节点

删除平衡操作:
void DeleteBalance(Node* n)
链接: https://www.jianshu.com/p/84416644c080.
在这里插入图片描述
代码:


void DeleteBalance(Node* n){
    //先删除,
    Node* p = n->dad;
    Node* s = (n->dad==NULL)?NULL:((n->dad->rson->keyvalue==n->keyvalue)?n->dad->lson:n->dad->rson);
    int sL1R0 = (s==NULL)?3:( (n->dad->lson->keyvalue==s->keyvalue)?1:0);
    Node* sl = (s==NULL)?NULL:(s->lson);
    Node* sr = (s==NULL)?NULL:(s->rson);
    if(n->Red1Black0==2){
        n->Red1Black0 = 0;
    }else{
        if(n->dad == NULL){
            n->keyvalue =0;
            n->cont =NULL;
        }else{
            if(sL1R0==1){
                n->dad->rson =NULL;
            }else{
                n->dad->lson =NULL;
            }
            //不知道为什么
            //free(n);
        }
    }
    //然后开始判断是否需要平衡
    if(n->dad==NULL){//n为根节点,无需平衡
        return;
    }else{
        if(s->Red1Black0!=1){//兄黑
            if(((s->rson==NULL)|| (s->rson->Red1Black0!=1  ))&&((s->lson==NULL)||(s->lson->Red1Black0!=1))){//兄子节点全黑
                if(p->Red1Black0!=1){//父黑
                    s->Red1Black0=1;
                    p->Red1Black0=2;
                    DeleteBalance(p);
                }else{//父红
                    p->Red1Black0 =0;
                    s->Red1Black0 =1;
                    //交换ps颜色,平衡结束
                }
            }else{//兄子节点不全黑
                //拐的时候,先弄直
                if((sL1R0==1) && (sr!=NULL) && (sr->Red1Black0==1 )){
                    sr->dad = p;
                    p->lson = sr;

                    s->rson = sr->lson;
                    if(sr->lson!=NULL) sr->lson->dad = s;

                    s->dad = sr;
                    sr->lson =s;

                    s->Red1Black0=1;
                    sr->Red1Black0 =0;
                }else if((sL1R0==0)&&(sl!=NULL)&&(sl->Red1Black0==1)){
                    sl->dad =p;
                    p->rson = sl;

                    s->lson = sl->rson;
                    if(sl->rson!=NULL)sl->rson->dad =s;

                    s->dad = sl;
                    sl->rson = s;

                    s->Red1Black0 =1;
                    sl->Red1Black0 =0;
                }
                //直的时候,直接处理
                if(sL1R0 ==1){//s在左边
                    Node* newP = (Node*)malloc(sizeof(Node));
                    newP->cont = (Content*)malloc(sizeof(Content));
                    newP->keyvalue = p->keyvalue;
                    ContCpy(newP->cont,p->cont);
                    p->keyvalue = s->keyvalue;
                    ContCpy(p->cont,s->cont);

                    newP->lson = sr;
                    if(sr!=NULL)sr->dad = newP;

                    newP->rson = p->rson;
                    if(p->rson!=NULL)p->rson->dad = newP;

                    sl->dad = p;
                    p->lson = sl;

                    newP->dad = p;
                    p->rson = newP;
                    sl->Red1Black0 = 0;
                }else{
                    Node* newP = (Node*)malloc(sizeof(Node));
                    newP->cont = (Content*)malloc(sizeof(Content));
                    newP->keyvalue = p->keyvalue;
                    ContCpy(newP->cont,p->cont);
                    p->keyvalue = s->keyvalue;
                    ContCpy(p->cont,s->cont);

                    newP->rson = sl;
                    if(sl!=NULL)sl->dad = newP;

                    newP->lson = p->lson;
                    if(p->lson!=NULL)p->lson->dad = newP;

                    sr->dad = p;
                    p->rson = sr;

                    newP->dad = p;
                    p->lson = newP;
                    sr->Red1Black0 = 0;
                }
            }
        }
    }
}

4查询节点

普普通通的递归查询

Node* FindNode(Node* root,int keyvalue) {
    if(root==NULL){return NULL;}
    if((root->keyvalue )== keyvalue){
        return root;
    }else{
        if(keyvalue>(root->keyvalue)){
            return FindNode(root->rson,keyvalue);
        }else{
            return FindNode(root->lson,keyvalue);
        }
    }
}

5遍历节点

普普通通的中序遍历

6以文件形式保存

函数指针形式,方便更换节点定义

int SaveRBTree(Node* root,char* filename, char* (*NodeToString)(Node* a)) {
    SomeNodes a = GetAllNodes(root, 1000);
    FILE * p = fopen(filename , "w");
    if(p==NULL){printf("file ERROR!\n"); return 0;}
    fprintf(p,"%d\n",a.num);
    for(int i=0; i < a.num ; i++){
        fprintf(p,"%s\n",NodeToString(a.datas[i]));
    }
    fclose(p);
    return a.num;
}
Node* LoadRBTree(char* filename, Node* (*StringToNode)(char* s)) {
    Node* root = CreatRBTree();
    int num;
    FILE* p=fopen(filename,"r");
    if(p==NULL){printf("file ERROR!\n"); return NULL;}
    fscanf(p,"%d",&num);
    char *one_line;
    one_line = (char*)malloc( 1000 * sizeof(char));
    for(int i=0;i<num+1;i++){
        fgets(one_line, 1000, p);
        AddNode(root,StringToNode(one_line));
    }
    printf("file Load Succeed: %d Nodes Loaded!\n",num);
    return root;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值