红黑树本身就是一课二叉查找树,就是多加了两个要求
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);
}