参照算法导论伪代码。
注释没有很详细,建议先看算法导论或者其他博主的分析搞清楚insert和delete操作的方法。
#include<stdio.h>
#include<stdlib.h>
typedef int type;
typedef enum Color //定义红黑树结点颜色颜色类型
{
red = 0,
black = 1
}Color;
typedef struct rbtree //定义红黑树的结构
{
Color color;
type key;
struct rbtree *left;
struct rbtree *right;
struct rbtree *parent;
}node, *tree;
node *nil = NULL; //创建一个哨兵结点。这里要用哨兵去让空的叶子结点的颜色是black的,参照红黑树的定义
node* create(type key, node *left, node *right, node *parent) //创建结点
{
node *p;
p = (node*)malloc(sizeof(node));
p->color = black; //默认颜色为black
p->left = left;
p->right = right;
p->parent = parent;
p->key = key;
/* printf("创造结点完毕");*/
return p;
}
void left_rotate(tree &t, node *x) //左旋,这个看图就能理解具体操作
{
node *y = x->right;
x->right = y->left;
if (y->left != nil)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == nil)
t = y;
else
{
if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
void right_rotate(tree &t, node *x) //右旋
{
node *y = x->left;
x->left = y->right;
if (y->right != nil)
y->right->parent = x;
y->parent = x->parent;
if (x->parent == nil)
t = y; //
else
{
if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
}
y->right = x;
x->parent = y;
}
node* search(tree &t, type key) //查找元素
{
node *x = t;
if (x == nil || x->key == key)
{
return t;
}
if (key < x->key)
{
return search(x->left, key);
}
else
{
return search(x->right, key);
}
} //递归查找
void rb_insert_fixup(tree &t, node* z)
{
node *y;
while ((z->parent != nil) && (z->parent->color == red)) //only when z's parent is red there will probably obey the red node has two black nodes
{
if (z->parent == z->parent->parent->left) //z'parent is the left node
{
y = z->parent->parent->right; //let y be z's uncle node
if (y->color == red) //parent and uncle and itself are all red
{
z->parent->color = black;
y->color = black;
z->parent->parent->color = red;
z = z->parent->parent; //let z up to its grandpa
}
else
{
if (z == z->parent->right) // z is a right node
{
z = z->parent;
left_rotate(t, z);
}
z->parent->color = black;
z->parent->parent->color = red;
right_rotate(t, z->parent->parent);
}
}
else //z's parent is the right node
{
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
{
if (z == z->parent->left) // z is a left node
{
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; //始终保持根节点是黑色
}
node* rb_insert(tree &t, node *z) //插入操作
{
if (t == NULL) //t是空的树
{
t = (tree)malloc(sizeof(node));
nil = (node*)malloc(sizeof(node)); //初始化哨兵结点
nil->color = black;
t->left = nil;
t->right = nil;
t->parent = nil;
t->key = z->key;
t->color = black;
}
else
{
node *y = nil;
node *x = t; //
while (x != nil)
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == nil)
t = z;
else
{
if (z->key < y->key)
y->left = z;
else
y->right = z;
}
z->left = nil;
z->right = nil;
z->color = red; //始终保持插入的结点是红色,不符合具体性质了再用fixup调整
rb_insert_fixup(t, z);
}
return t;
}
node* rb_insert_(tree &t, type k)
{
node *z;
z = create(k, NULL, NULL, NULL);
return rb_insert(t, z);
}
node* min(tree &m) //最小值
{
node *n = m;
if (n == nil)
return nil;
while (n->left != nil)
{
n = n->left;
}
return n;
}
node* successor(node *s) //后继
{
node *p;
if (s->right != nil) //结点右子树非空
{
return min(s->right);
}
else
{
p = s->parent; //结点是左孩子,后继就是他的父节点
while (p != nil && p->right == s)
{ //结点是右孩子,向上查找,直到遇到一个有左孩子的父节点,那就是后继
{
s = p;
p = p->parent;
}
}
return p;
}
}
void rb_delete_fixup(tree &t, node *x)
{
node *w;
while (x != t && x->color == black) //
{
if (x == x->parent->left)
{
w = x->parent->right;
if (w->color == red)
{
w->color = black;
x->parent->color = red;
left_rotate(t, x->parent);
w = x->parent->right;
}
if (w->left->color == black && w->right->color == black)
{
w->color = red;
x = x->parent;
}
else if (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; //
}
else
{
w = x->parent->left;
if (w->color = red)
{
w->color = black;
x->parent->color = red;
right_rotate(t, x->parent);
w = x->parent->left;
}
if (w->left->color == black && w->right->color == black)
{
w->color = red;
x = x->parent;
}
else if (w->left->color == black)
{
w->right->color = black;
w->color = red;
left_rotate(t, w);
w = x->parent->right;
}
w->color = x->parent->color;
x->parent->color = black;
w->left->color= black;
right_rotate(t, x->parent);
x = t; //
}
}
x->color = black;
}
node* rb_delete(tree &t, node *z)
{
node *y, *x;
node *m=nil;
node* n = z;
if (z->left == nil || z->right == nil)
y = z;
else
y = successor(n); //这一行使z的右孩子发生变化
if (y->left != nil)
x = y->left;
else
x = y->right;
x->parent = y->parent;
if (y->parent == nil)
t = x; //
else
{
if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
}
if (y != z)
{
z->key = (y->key);
}
if (y->color == black)
rb_delete_fixup(t, x);
return t;
}
node* rb_delete_(tree &t, type k)
{
node *z;
z = search(t, k);
if (z != nil)
{
t = rb_delete(t, z);
}
else
printf("无此元素");
return t;
}
void print_tree(tree &t) //中序遍历打印
{
if (t != nil && t != NULL)
{
print_tree(t->left);
printf("%7d , %5d\n ", t->key, t->color);
print_tree(t->right);
}
}
int main()
{
int i;
tree zz = NULL, mm = NULL, nn = NULL, xx = NULL, yy = NULL;
type k;
int a[12] = {3,12,15,17,19,55,20,18,36,48,31,29 };
printf("\n原来的数字是:----------------------------------------\n");
for (i = 0; i<12; i++)
{
printf("%d ", a[i]);
zz = rb_insert_(zz, a[i]);
}
printf("\n中序遍历是:-------------------------------------------\n");
printf("规定:red=0,black=1\n");
print_tree(zz);
printf("\n要删除的值是:---------------------------------------");
scanf_s("%d", &k);
yy = rb_delete_(zz, k);
print_tree(yy);
printf("\n要插入的值是:--------------------------------------");
scanf_s("%d", &k);
rb_insert_(zz, k);
print_tree(zz);
}
过程中遇到的问题:
1.开始不知道有枚举类型,不知道怎么定义color,用了#define结果总是报错
2.开始没有使用哨兵元素,会导致在逐渐插入的过程中,检验父节点,祖父节点或叔叔结点可能碰到空的时候那个NULL是没有颜色的,运行到这里就中断了。所以必须事先定义好哨兵nil。
3.算法导论上的伪代码结构不算清晰,就是if else 那些嵌套写的不太清楚,得理清楚逻辑结构了才能自己写对。
4.导论上的地方省略了结构相似的部分,x == x->parent->left,->right就省略了,看起来不需要动脑子,其实还是容易写错的
5.学习方式应该是有问题的,先看的算法导论,把思路理得清楚一些了,然后看的网上的解析更明白一些了,但是还是体现在被动的去看懂。然后再去根据导论的伪代码实现,结果又很多bug,改了一些,然后又找了红黑树的现成代码参照修改,把它改出来了。但是这样学习感觉还是很被动的再接受,从翻译伪代码到debug,其实进步并不大,现在要自己不参照伪代码写出来还是不行。甚至不看书复述红黑树的基本思想也不能完整想出来。所以这样是有很多问题的,今后要改进。。。