红黑树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);
}

posted on 2013-04-02 21:03  紫金树下  阅读(197)  评论(0编辑  收藏  举报