按算法导论里的伪代码用C++实现了红黑树。实现过程中,参考了nginx的红黑树实现,特别是右旋的实现,算法导论里没有给出,就借鉴了nginx的实现。
对比了nginx的红黑树实现和算法导论里的伪代码,插入基本上一样的,删除两者有点差别,但思路应该是一样的。
实现过程中需要注意的是,空叶子结点一定要实现,不能用空指针替代,不然会出现空指针错误。
class rb_tree_node
{
public:
rb_tree_node(int k)
: parent(NULL)
, left(NULL)
, right(NULL)
, key(k)
, color(0)
{}
int key;
int color;
rb_tree_node* parent;
rb_tree_node* left;
rb_tree_node* right;
};
class rb_tree
{
public:
rb_tree() {
null_end = new rb_tree_node(0);
root = null_end;
}
void insert(rb_tree_node* z);
void rb_delete(rb_tree_node* z);
void inorder_tree_walk(rb_tree_node* x);
rb_tree_node* search(rb_tree_node* x, int k);
rb_tree_node* minimum(rb_tree_node* x);
void left_rotate(rb_tree_node* x);
void right_rotate(rb_tree_node* x);
void insert_fixup(rb_tree_node* z);
void transplant(rb_tree_node* u, rb_tree_node* v);
void delete_fixup(rb_tree_node* x);
rb_tree_node* root;
rb_tree_node* null_end;
};
bool rb_tree_node_is_red(rb_tree_node* node)
{
return node->color == 1;//1-red, 0-black
}
bool rb_tree_node_is_black(rb_tree_node* node)
{
return !rb_tree_node_is_red(node);
}
void rb_tree::left_rotate(rb_tree_node* x)
{
rb_tree_node* y = x->right;
x->right = y->left;
if (y->left != null_end)
{
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == null_end)
{
root = y;
}
else if (x == x->parent->left)
{
x->parent->left = y;
}
else
{
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
void rb_tree::right_rotate(rb_tree_node* node)
{
rb_tree_node *temp;
temp = node->left;
node->left = temp->right;
if (temp->right != null_end) {
temp->right->parent = node;
}
temp->parent = node->parent;
if (node->parent == null_end) {
root = temp;
}
else if (node == node->parent->right) {
node->parent->right = temp;
}
else {
node->parent->left = temp;
}
temp->right = node;
node->parent = temp;
}
void rb_tree::insert(rb_tree_node* z)
{
rb_tree_node* y = null_end;
rb_tree_node* x = root;
while (x != null_end)
{
y = x;
if (z->key < x->key)
{
x = x->left;
}
else
{
x = x->right;
}
}
z->parent = y;
if (y == null_end)
{
root = z;
}
else if(z->key < y->key)
{
y->left = z;
}
else
{
y->right = z;
}
z->left = null_end;
z->right = null_end;
z->color = 1;
insert_fixup(z);
}
void rb_tree::rb_delete(rb_tree_node* z)
{
rb_tree_node* y = z;
int y_ori_color = y->color;
rb_tree_node* x;
if (z->left == null_end)
{
x = z->right;
transplant(z, z->right);
}
else if (z->right == null_end)
{
x = z->left;
transplant(z, z->left);
}
else
{
y = minimum(z->right);
y_ori_color = y->color;
x = y->right;
if (y->parent == z)
{
x->parent = y;
}
else
{
transplant(y, y->right);
y->right = z->right;
y->right->parent = y;
}
transplant(z, y);
y->left = z->left;
y->left->parent = y;
y->color = z->color;
}
if (y_ori_color == 0)
{
delete_fixup(x);
}
delete z;
}
void rb_tree::inorder_tree_walk(rb_tree_node* x)
{
if (x != null_end )
{
inorder_tree_walk(x->left);
printf("key:%d, color:%d, parent:%d\n", x->key, x->color, x->parent->key);
inorder_tree_walk(x->right);
}
}
rb_tree_node* rb_tree::search(rb_tree_node* x, int k)
{
if (x == null_end || x->key == k)
{
return x;
}
if (k < x->key)
{
return search(x->left, k);
}
else
{
return search(x->right, k);
}
}
rb_tree_node* rb_tree::minimum(rb_tree_node* x)
{
while (x->left != null_end)
x = x->left;
return x;
}
void rb_tree::insert_fixup(rb_tree_node* z)
{
while ( rb_tree_node_is_red(z->parent) )
{
if (z->parent == z->parent->parent->left)
{
rb_tree_node* y = z->parent->parent->right;
if ( rb_tree_node_is_red(y) )
{
z->parent->color = 0;
y->color = 0;
z->parent->parent->color = 1;
z = z->parent->parent;
}
else
{
if (z == z->parent->right)
{
z = z->parent;
left_rotate(z);
}
z->parent->color = 0;
z->parent->parent->color = 1;
right_rotate(z->parent->parent);
}
}
else
{
rb_tree_node* y = z->parent->parent->left;
if ( rb_tree_node_is_red(y) )
{
z->parent->color = 0;
y->color = 0;
z->parent->parent->color = 1;
z = z->parent->parent;
}
else
{
if (z == z->parent->left)
{
z = z->parent;
right_rotate(z);
}
z->parent->color = 0;
z->parent->parent->color = 1;
left_rotate(z->parent->parent);
}
}
}
root->color = 0;
}
void rb_tree::transplant(rb_tree_node* u, rb_tree_node* v)
{
if (u->parent == null_end)
{
root = v;
}
else if (u == u->parent->left)
{
u->parent->left = v;
}
else
{
u->parent->right = v;
}
v->parent = u->parent;
}
void rb_tree::delete_fixup(rb_tree_node* temp)
{
while (temp != root && rb_tree_node_is_black(temp))
{
if (temp == temp->parent->left)
{
rb_tree_node* w = temp->parent->right;
if (rb_tree_node_is_red(w))
{
w->color = 0;
temp->parent->color = 1;
left_rotate(temp->parent);
w = temp->parent->right;
}
if ( rb_tree_node_is_black(w->left) &&
rb_tree_node_is_black(w->right) )
{
w->color = 1;
temp = temp->parent;
}
else
{
if (rb_tree_node_is_black(w->right))
{
w->left->color = 0;
w->color = 1;
right_rotate(w);
w = temp->parent->right;
}
w->color = temp->parent->color;
temp->parent->color = 0;
w->right->color = 0;
left_rotate(temp->parent);
temp = root;
}
}
else
{
rb_tree_node* w = temp->parent->left;
if (rb_tree_node_is_red(w))
{
w->color = 0;
temp->parent->color = 1;
right_rotate(temp->parent);
w = temp->parent->left;
}
if (rb_tree_node_is_black(w->right) &&
rb_tree_node_is_black(w->left))
{
w->color = 1;
temp = temp->parent;
}
else
{
if (rb_tree_node_is_black(w->left))
{
w->right->color = 0;
w->color = 1;
left_rotate(w);
w = temp->parent->left;
}
w->color = temp->parent->color;
temp->parent->color = 0;
w->left->color = 0;
right_rotate(temp->parent);
temp = root;
}
}
}
temp->color = 0;
}