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