zoukankan      html  css  js  c++  java
  • 红黑树c实现

    参考算法导论

    #include<stdio.h>
    #include<time.h>
    #include<stdlib.h>

    typedef int KEY;

    enum NodeColor
    {
        BLACK=0,
        RED=1
    };

    /*定义节点*/
    typedef struct node
    {
        int          data;
        struct node* parent;
        struct node* left;
        struct node* right;
        enum    NodeColor    color;
    }RBTree,*PRBTree;

    /*标志位节点 NIL[T]*/
    PRBTree NIL_FLAG=NULL;

    /*在红黑树上的操作*/
    static void rb_insert(PRBTree*,int);
    static PRBTree rb_insert_fixup(PRBTree*,PRBTree);

    static void rb_delete(PRBTree*,PRBTree);
    static void rb_delete_fixup(PRBTree*,PRBTree);

    static void left_rotate(PRBTree *T,PRBTree x);
    static void right_rotate(PRBTree *T,PRBTree x);

    void inorder(PRBTree);
    void inorder_delete(PRBTree);

    //初始化 NIL[T]
    static void init_flag()
    {
            NIL_FLAG=(PRBTree)malloc(sizeof(RBTree));
            NIL_FLAG->parent=NULL;
            NIL_FLAG->left=NULL;
            NIL_FLAG->right=NULL;
            NIL_FLAG->color=BLACK;//NIL节点是黑色的
            NIL_FLAG->data=-1; //随便设置一个就行了
    }

    /*左旋转*/
    void left_rotate(PRBTree *root,PRBTree x) //对x节点进行左旋转,要求x的右孩子不是NIL[T]
    {
        PRBTree y=NULL;

        y=x->right;
        if(y!=NIL_FLAG)
        {
            x->right=y->left;
            if(y->left!=NIL_FLAG)
                y->left->parent=x;
            y->parent=x->parent;
            if(x->parent==NIL_FLAG)
                *root=y;
            else
            {
                if(x==x->parent->left)
                    x->parent->left=y;
                else
                    x->parent->right=y;    
            }
            y->left=x;
            x->parent=y;
        }
        else
        {
            printf("不能进行左旋转\n");
            return ;
        }
    }

    /*右旋转*/
    void right_rotate(PRBTree* root,PRBTree x)
    {
        PRBTree y=NULL;
        
        y=x->left;
        if(y!=NIL_FLAG)
        {
            x->left=y->right;
            if(y->right!=NIL_FLAG)
                y->right->parent=x;
            y->parent=x->parent;
            if(x->parent==NIL_FLAG)
                *root=y;
            else
            {
                if(x==x->parent->left)
                    x->parent->left=y;
                else
                    x->parent->right=y;
            }
            y->right=x;
            x->parent=y;
        }
    }

    /*插入修改*/
    static PRBTree rb_insert_fixup(PRBTree* T,PRBTree z)
    {
        PRBTree y=NULL;
        while(z->parent->color==RED) //z是红色并且当z的父节点是红色的时候
        {
            //第1种情况,若z的父节点是祖父节点的左孩子,又分3种
            if(z->parent==z->parent->parent->left)
            {
                y=z->parent->parent->right;//y是z的叔叔节点
                if(y->color==RED)//y是红色的
                {
                    z->parent->color=BLACK;
                    y->color=BLACK;
                    z->parent->parent->color=RED;
                    z=z->parent->parent;
                }
                else//y是黑色的,判断z是z->parent的左还是右孩子
                {
                    if(z==z->parent->right)
                    {
                        z=z->parent;
                        left_rotate(T,z);
                    }//变换之后z变成z->parent的左孩子了,并且z红,z->parent红,z->parent->parent黑
                    z->parent->color=BLACK;
                    z->parent->parent->color=RED;
                    right_rotate(T,z->parent->parent);// 右旋转z的祖父节点
                }
            }
            else//第2种情况,z的父节点是z祖父节点的右孩子
            {
                    y=z->parent->parent->left;
                    if(y->color==RED)
                    {
                        z->parent->color=BLACK;
                        y->color=BLACK;
                        z->parent->parent->color=RED;
                        z=z->parent->parent;
                    }
                    else//y是黑色的
                    {
                        if(z==z->parent->left)
                        {
                            z=z->parent;
                            right_rotate(T,z);
                        }
                        z->parent->color=BLACK;
                        z->parent->parent->color=RED;
                        left_rotate(T,z->parent->parent);
                    }
            }
        }
        //上述循环过后,唯一可能违反红黑树性质的就是根结点的颜色
        (*T)->color=BLACK;
        return *T;
    }

    /*插入*/
    static  void rb_insert(PRBTree *T,int data)
    {
        //初始化z节点
        PRBTree z=(PRBTree)malloc(sizeof(RBTree));
        if(!z)
        {
            printf("申请节点失败\n");
            return ;
        }
        z->data=data;
        z->parent=NIL_FLAG;
        z->left=NIL_FLAG;
        z->right=NIL_FLAG;
        z->color=RED; //新的节点设置成红色

        PRBTree y,x;
        y=NIL_FLAG;
        x=*T;

        while(x!=NIL_FLAG)
        {
            y=x;
            if(z->data<=x->data)
                x=x->left;
            else
                x=x->right;
        }

        z->parent=y;
        if(y==NIL_FLAG)//第一次插入节点
            *T=z;
        else
        {
            if(z->data<=y->data)
                y->left=z;
            else
                y->right=z;
        }

        rb_insert_fixup(T,z);
        //返回这个根节点
    }

    /*删除调整*/
    static void rb_delete_fixup(PRBTree* T,PRBTree x)//循环中,x始终指向有双重黑色节点的非根节点
    {
        PRBTree w;
        while( x!=*T && x->color==BLACK)
        {
            if(x==x->parent->left)//第1种,x是p[x]的左孩子
            {
                w=x->parent->right;
                //对兄弟节点w的情况有4种
                if(w->color==RED)
                {
                    w->color=BLACK;
                    x->parent->color=RED;
                    left_rotate(T,x->parent);
                    w=x->parent->right;//新的w节点
                }//w是红色结束
                else//w是黑色的
                {
                    if(w->left->color==BLACK && w->right->color==BLACK)//w的两个孩子节点都是黑色
                    {
                        w->color=RED;
                        x=x->parent;
                    }
                    else if(w->left->color==RED && w->right->color==BLACK)
                    {
                        w->left->color=BLACK;
                        w->color=RED;
                        right_rotate(T,w);
                        w=x->parent->right;
                    }

                    w->color=x->parent->color;
                    x->parent->color=BLACK;
                    w->right->color=BLACK;
                    left_rotate(T,x->parent);
                    x=*T;
                }//w是黑色结束
            }
            else//如果x是p[x]的右孩子
            {
                w=x->parent->left;
                if(w->color==RED)
                {
                    w->color=BLACK;
                    x->parent->color=RED;
                    right_rotate(T,x->parent);
                    w=x->parent->left;
                }
                else
                {
                    if(w->left->color==BLACK && w->right->color==BLACK)
                    {
                        w->color=RED;
                        x=x->parent;
                    }else if(w->left->color==BLACK && w->right->color==RED)
                    {
                        w->right->color=BLACK;
                        w->color=RED;
                        left_rotate(T,w);
                        w=x->parent->left;
                    }    

                    w->color=x->parent->color;
                    x->parent->color=BLACK;
                    w->left->color=BLACK;
                    right_rotate(T,x->parent);
                    x=*T;
                }
            }
        }//while结束
        x->color=BLACK;//x指向根或者指向一个红黑节点(自身是红色),那么把x染成黑色
    }

    /*查找中序后继*/
    static PRBTree tree_successor(PRBTree T,PRBTree z)//z肯定有右孩子
    {
        PRBTree y;
        y=z->right;
        while(y->left!=NIL_FLAG)
            y=y->left;
        return y;
    }

    /*删除节点*/
    static void rb_delete(PRBTree *T,PRBTree z)
    {
        //参考二叉树中删除
        PRBTree y,x;
        if(z->left==NIL_FLAG || z->right==NIL_FLAG)//z至少有一个孩子
            y=z;
        else
            y=tree_successor(*T,z);

        if(y->left!=NIL_FLAG)
            x=y->left;
        else
            x=y->right;
        //此时x可能是y的一个孩子,也有可能是NIL_FLAG,若x是NIL_FLAG,那么y就是没有孩子节点
        x->parent=y->parent;
        if(y->parent==NIL_FLAG)
            *T=x;
        else
        {
            if(y==y->parent->left)
                y->parent->left=x;
            else
                y->parent->right=x;
        }
        if(y!=z) // z有2个孩子情况,y是z的后继节点
        {
            z->data=y->data;
        }

        if(y->color==BLACK)
            rb_delete_fixup(T,x);
        free(y);
    }

    /*中序遍历*/
    void inorder(PRBTree T)
    {
        if(T!=NIL_FLAG)//没有节点指向null,叶子节点都被NIL_FLAG代替
        {
            inorder(T->left);
            printf("%d ",T->data);
            inorder(T->right);
        }
    }

    /*中序删除*/
    void inorder_delete(PRBTree T)
    {
        if(T!=NIL_FLAG)
        {
            inorder_delete(T->left);
            PRBTree temp=T->right;
            free(T);
            T=NULL;
            inorder_delete(temp);
        }
    }

    void main()
    {
        int i;

        srand(time(NULL));
        init_flag();

        PRBTree root=NIL_FLAG; //刚开始根节点指向这个

        for(i=0;i<20;i++)
            rb_insert(&root,rand()%10000);

        inorder(root);
        printf("\n");
        rb_delete(&root,root->left);
        inorder(root);
        printf("\n");
        inorder_delete(root);
    }

  • 相关阅读:
    洛谷P2740 草地排水
    BZOJ 4326 运输计划
    BZOJ 1036 树的统计
    BZOJ 1003 物流运输
    BZOJ 1251 序列终结者
    HDU4864 Task(算竞进阶习题)
    洛谷P4281 紧急集合 / 聚会
    CH0802 占卜DIY
    node.js(二)各种模块
    node.js对象数据类型
  • 原文地址:https://www.cnblogs.com/buxianghe/p/2996490.html
Copyright © 2011-2022 走看看