红黑树的插入和删除

//本工程在visual studio下能看完整的图,利用graphviz作图工具,保证graphviz添加到环境变量中

#include <stdio.h>
#include <stdlib.h>

typedef struct rbnode{
	int key;
	char color;
	struct rbnode *parent;
	struct rbnode *left;
	struct rbnode *right;
}rbnode_t;

//定义根和nil节点
rbnode_t *nil, *root;

//右旋
/*
*	    x			    y
*	   / \			   / \
*	  y   c   -->  	  a   x
*	 / \			      / \
*	a   b 			     b   c
*
*/
void right_rotate(rbnode_t *x){
	//右旋以x和x的左儿子为轴进行旋转
	rbnode_t *y = x->left;
	x->left = y->right;
	if(y->right != nil)
		y->right->parent = x;
	y->parent = x->parent;
	if(x->parent == nil)
		root = y;
	else if(x == x->parent->left)
		x->parent->left = y;
	else
		x->parent->right = y;
	x->parent = y;
	y->right = x;
}


/**
*	左旋,以x和x的右节点为轴进行旋转
*		 x					 y
*		/ \					/ \
*	       a   y        --->                    x   c
*		  / \			             / \
*		 b   c 			    a   b
*/
void left_rotate(rbnode_t *node){
	rbnode_t *y = node->right;
	node->right = y->left;
	if(y->left != nil)
		y->left->parent = node;
	y->parent = node->parent;
	if(node->parent == nil){
		root = y;
	}else if(node == node->parent->left){
		node->parent->left = y;
	}else{
		node->parent->right = y;
	}
	y->left = node;
	node->parent = y;
}

/**
	节点插入后,红黑树的查找性质m没有被破坏,但是红黑性质被破坏.该函数调整红黑性质
*/
void adjust_tree(rbnode_t *node){
	while(node->parent->color == 'r'){
		if(node->parent == node->parent->parent->left){
			rbnode_t *y = node->parent->parent->right;
			/**
			 * 如果node父亲b是祖父a的左孩子,并且叔叔c是黑色,那么变换如下
			 *	  		   a(b)			node->a(r)                 :祖父节点变红
			 *	  		  /   \					   /   \
			 *	  		b(r)   c(r)  --->   	       b(b)   c(b)           :父亲和叔叔变黑
			 *	  	      /						/
			 *     node-> d(r)				    d(r)			 :当前指针晚上移到祖父节点
			 *	  	 									 :祖父节点b变为新的node节点
			 * 	 r表示红色,b表示黑色
			 */
			if(y->color == 'r'){
				node->parent->color = 'b';
				y->color = 'b';
				node->parent->parent->color = 'r';
				node = node->parent->parent;
			}
			else
			{
				/**
				 * 如果node的叔叔是黑色,当前节点node是其父亲的右孩子,那么当前节点上移一位,然后在当前节点执行左旋转
				 *			  a(r)                 	                  a(r)
				 *			  /   \ 					  /   \
				 *		     b(r)  c(b)    --->                          d(r)  c(b)
				 *		       \					    /
				 * 		 node-> d(r) 			        b(r) <-node
				 *
				 * 简单理解就是旋转使得当前节点(b)和其父节点(d)以及祖父节点(a)成一条线,然后转为下面这种情况执行右旋
				 */
				if(node == node->parent->right){
					node = node->parent;
					left_rotate(node);
				}
				/**
				 * 把当前节点父节点涂成黑色,祖父节点涂成红色,右旋其祖父节点a
				 *	    	  a(b)                 	                  b(b)
				 *	    	  /   \ 					  /   \
				 *	         b(r)  c(b)    --->                       d(r)  a(r)
				 *	        /  					       		   \
				 * node-> d(r) 			           		        c(b)
				 *
				 */
				node->parent->color = 'b';
				node->parent->parent ->color = 'r';
				node = node->parent->parent;
				right_rotate(node);
			}
		}else{
			/**
			 * 当前节点父亲是其祖父的右孩子时,与上面分析对称
			 */
			rbnode_t *y = node->parent->parent->left;
			if(y->color == 'r'){
				node->parent->color = 'b';
				y->color = 'b';
				node->parent->parent->color = 'r';
				node = node->parent->parent;
			}
			else{
				if(node == node->parent->left){
					node = node->parent;
					right_rotate(node);
				}
				node->parent->color = 'b';
				node->parent->parent->color = 'r';
				node = node->parent->parent;
				left_rotate(node);
			}
		}
	}
	root->color = 'b';
}

void insert(int key){
	rbnode_t *parent = nil, *point = root;
	while(point != nil){
		parent = point;
		if(key < point->key)
			point = point->left;
		else
			point = point->right;
	}

	rbnode_t *node = (rbnode_t*)malloc(sizeof(rbnode_t));
	node->key = key;
	node->color = 'r';
	node->left = nil;
	node->right = nil;

	node->parent = parent;
	if(parent == nil)
		root = node;
	else if(key < parent->key)
		parent->left = node;
	else
		parent->right = node;

	adjust_tree(node);
}

void build_tree(int *array, int size){
	nil = (rbnode_t*)malloc(sizeof(rbnode_t));
	nil->color = 'b';
	nil->left = nil->right = nil->parent = NULL;
	nil->key = 0;
	root = nil;
	for(int i = 0; i < size; ++i){
		insert(array[i]);
	}
}

FILE *fp;

void dfs(rbnode_t *node){
	fprintf(fp, "\t%d[color=%s];\n", node->key, node->color == 'r' ? "red" : "black");
	if(node->left != nil){
		fprintf(fp, "\t%d->%d;\n", node->key, node->left->key);
		dfs(node->left);
	}
	if(node->right != nil){
		fprintf(fp, "\t%d->%d;\n", node->key, node->right->key);
		dfs(node->right);
	}
}

void print_tree(){
	fp = fopen("test.dot", "w");
	fprintf(fp, "digraph G {\n");
	dfs(root);
	fprintf(fp, "}");
	fclose(fp);
	system("dot -Tpng -o test.png test.dot");
	system("start test.png");
}

rbnode_t *tree_minmun(rbnode_t *x){
	while(x->left != nil)
		x = x->left;
	return x;
}

rbnode_t *successor(rbnode_t *x){
	rbnode_t *y;

	if(x->right != nil)
		return tree_minmun(x->right);

	y = x->parent;
	while(y != nil && x == y->right){
		x = y;
		y = y->parent;
	}

	return y;

	while(x->left != nil){
		y = x;
		x = x->left;
	}
	return y;
}

void delete_fixup(rbnode_t *x){
	while(x != root && x->color == 'b'){
		rbnode_t *w;
		if(x == x->parent->left){
			w = x->parent->right;
			if(w->color == 'r'){
				w->color = 'b';
				w->parent->color = 'r';
				left_rotate(x->parent);
				w = x->parent->right;
			}
			if(w->left->color == 'b' && w->right->color == 'b'){
				w->color = 'r';
				x = x->parent;
			}
			else{
				if(w->right->color == 'b'){
					w->left->color = 'b';
					w->color = 'r';
					right_rotate(w);
					w = x->parent->right;
				}
				w->color = x->parent->color;
				x->parent->color = 'b';
				w->right->color = 'b';
				left_rotate(x->parent);
				x = root;
			}
		}
		else{
			w = x->parent->left;
			if(w->color == 'r'){
				w->color = 'b';
				w->parent->color = 'r';
				right_rotate(x->parent);
				w = x->parent->left;
			}
			if(w->left->color == 'b' && w->right->color == 'b'){
				w->color = 'r';
				x = x->parent;
			}
			else{
				if(w->left->color == 'b'){
					w->right->color = 'b';
					w->color = 'r';
					left_rotate(w);
					w = x->parent->left;
				}
				w->color = x->parent->color;
				x->parent->color = 'b';
				w->left->color = 'b';
				right_rotate(x->parent);
				x = root;
			}
		}
	}
	x->color = 'b';
}

void rb_delete(rbnode_t *z){
	rbnode_t *y, *x;

	if(z->left == nil || z->right == nil)
		y = z;
	else
		y = successor(z);

	if(y->left != nil)
		x = y->left;
	else
		x = y->right;

	x->parent = y->parent;

	if(y->parent == nil)
		root = 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 == 'b')
		delete_fixup(x);
}

rbnode_t *rb_find(int key){
	rbnode_t *x = root;
	while(x != nil){
		if(key < x->key){
			x = x->left;
		}else if(key > x->key){
			x = x->right;
		}else{
			return x;
		}
	}
}

int main(int argc, char const *argv[])
{
	int array[] = {12, 1, 9, 2, 0, 11, 7, 19, 4, 15, 18, 5, 14, 13, 10, 16, 6, 3, 8, 17};
	int size = sizeof(array)/sizeof(array[0]);
	build_tree(array, size);
	print_tree();
	for(int i = 0; i < size - 1; ++i){
		rbnode_t *node = rb_find(array[i]);

		rb_delete(node);

		print_tree();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值