红黑二叉搜索树定义:
1.每个结点或者为红,或者为黑
2.根结点为黑
3.红结点只能有黑结点子女
4.对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点
红黑树数据结构的实现:
定义数据结构:
#define RED_COLOR 0
#define BLACK_COLOR 1
typedef struct red_black_tree_node
{
int color;
int data;
red_black_tree_node *left;
red_black_tree_node *right;
red_black_tree_node *parent;
}red_black_tree_node, *p_red_black_tree_node;
red_black_tree_node *root_node = NULL;
创建红黑树:
void create_red_black_tree(int array_data[], int array_length)
{
red_black_tree_node *p;
for(int i = 0; i < array_length; i++)
{
p = new (red_black_tree_node);
if(p != NULL)
{
p->color = RED_COLOR;
p->data = array_data[i];
p->left = NULL;
p->right = NULL;
}
red_black_tree_insert(p);
}
}
void red_black_tree_insert(red_black_tree_node *p)
{
if(root_node == NULL)
{
p->parent = NULL;
p->color = BLACK_COLOR;
root_node = p;
}
else
{
red_black_tree_node *temp;
temp = root_node;
while(temp != NULL)
{
if(p->data <= temp->data) //left sub-tree
{
if(temp->left != NULL)
{
temp = temp->left;
}
else
{
p->parent = temp;
temp->left = p;
break;
}
}
else //right sub-tree
{
if(temp->right != NULL)
{
temp = temp->right;
}
else
{
p->parent = temp;
temp->right = p;
break;
}
}
}
}
red_black_tree_insert_fixup(p);
}
void red_black_tree_insert_fixup(red_black_tree_node *p)
{
while((p->parent != NULL) && (p->parent->color == RED_COLOR))
{
//left sub red-black tree
if((p->parent->parent != NULL) && (p->parent == p->parent->parent->left))
{
//case 1: has right red uncle
//uncle_node = p->parent->parent->right
if((p->parent->parent->right != NULL) && (p->parent->parent->right->color == RED_COLOR))
{
p->parent->color = BLACK_COLOR;
p->parent->parent->right->color = BLACK_COLOR;
p->parent->parent->color = RED_COLOR;
p = p->parent->parent;
}
else //no right red uncle(has right black uncle)
{
//p is right child
if(p == p->parent->right)
{
p = p->parent;
left_rotate(p);
}
p->parent->color = BLACK_COLOR;
p->parent->parent->color = RED_COLOR;
right_rotate(p->parent->parent);
}
}
else if((p->parent->parent != NULL) && (p->parent == p->parent->parent->right)) //right sub red-black tree
{
//case 1: has left red uncle
if((p->parent->parent->left != NULL) && (p->parent->parent->left->color == RED_COLOR))
{
p->parent->color = BLACK_COLOR;
p->parent->parent->left->color = BLACK_COLOR;
p->parent->parent->color = RED_COLOR;
p = p->parent->parent;
}
else //no left red uncle(has right black uncle)
{
if(p == p->parent->left)
{
p = p->parent;
right_rotate(p);
}
p->parent->color = BLACK_COLOR;
p->parent->parent->color = RED_COLOR;
left_rotate(p->parent->parent);
}
}
}
root_node->color = BLACK_COLOR;
}
void left_rotate(red_black_tree_node *node)
{
if(node != NULL)
{
red_black_tree_node *right_node = node->right;
red_black_tree_node *parent = node->parent;
if(right_node != NULL)
{
node->right = right_node->left;
if(right_node->left != NULL)
{
right_node->left->parent = node;
}
right_node->parent = node->parent;
if(parent != NULL)
{
if(node == parent->left)
{
parent->left = right_node;
}
else
{
parent->right = right_node;
}
}
else
{
root_node = right_node;
}
node->parent = right_node;
right_node->left = node;
}
}
}
void right_rotate(red_black_tree_node *node)
{
if(node != NULL)
{
red_black_tree_node *left_node = node->left;
red_black_tree_node *parent = node->parent;
if(left_node != NULL)
{
node->left = left_node->right;
if(left_node->right != NULL)
{
left_node->right->parent = node;
}
left_node->parent = node->parent;
if(parent != NULL)
{
if(node == parent->left)
{
parent->left = left_node;
}
else
{
parent->right = left_node;
}
}
else
{
root_node = left_node;
}
node->parent = left_node;
left_node->right = node;
}
}
}
以上实现了红黑树的创建.创建红黑树的难点是插入一个新结点后,需要做一些调整.
插入的每一个新结点的颜色都为红色.如果父结点为黑色,则不必调整.如果父结点为红色(爷爷结点肯定为黑色),
对插入的新结点,调整时需要考虑六种情况:
1. 父结点是爷爷结点的左结点,叔叔(爷爷结点的右结点)是红色的.将父结点与叔叔结点颜色由红色改为黑色,
爷爷结点颜色改为红色.将爷爷结点再看做新插入结点继续进行调整.
2. 父结点是爷爷结点的左结点,叔叔(爷爷结点的右结点)是黑色的或者没有叔叔结点.如果新插入节点为父亲
的右结点,则父亲节点做一次左旋转并且此父亲节点做为新插入的结点继续调整
3. 父结点是爷爷结点的左结点,叔叔(爷爷结点的右结点)是黑色的或者没有叔叔结点,如果新插入节点为父亲
的左结点.修改父亲结点为黑色,爷爷结点为红色,爷爷结点做一次右旋转,调整完毕
4. 父结点是爷爷结点的右结点,叔叔(爷爷结点的左结点)是红色的.将父结点与叔叔结点颜色由红色改为黑色,
爷爷结点颜色改为红色.将爷爷结点看做新插入结点继续调整.
5. 父结点是爷爷结点的右结点,叔叔(爷爷结点的左结点)是黑色的或者没有叔叔结点.如果新插入节点为父亲
的左结点,则父亲节点做一次右旋转并且此父亲结点做为新插入的结点继续调整
6. 父结点是爷爷结点的右结点,叔叔(爷爷结点的左结点)是黑色的或者没有叔叔结点,如果新插入节点为父亲
的右结点.修改父亲结点为黑色,爷爷结点为红色,爷爷结点做一次左旋转,调整完毕
由此看来,红黑树是一种比较复杂的数据结构,需要很小心的构建.
以上所有代码,是根据<<算法导论>>一书的伪代码修改而来并且测试过.