转载请注明出处:http://blog.csdn.net/mxway/article/details/38080315

以下维基百科上红黑树的5个性质

1.      节点是红色或黑色

2.      根是黑色

3.      全部叶子都是黑色(叶子是NIL节点)

4.      每一个红色节点必须有两个黑色的子节点。

(从每一个叶子到根的全部路径上不能有两个连续的红色节点。

5.      从任一节点到其每一个叶子的全部简单路径都包括同样数目的黑色节点。

依据上面的5个性质,我们能够得出以下的结论:

结论1:在红黑树中若x仅仅有一棵非空子树。则x必为黑色。


证明:如果x为红色,依据性质4能够推出x有两个黑色子节点。与x仅仅有一棵非空子树矛盾。

结论2:在红黑树中若x仅仅有一棵非空子树。则该非空子树的根必为红色,且该非空子树仅且仅仅有一个根节点。

证明:如果y为x的左孩子。节点y的颜色为黑色,且y有子树。

由于y是黑色。x的右子权为空,所以从x到其左子树各叶子结点的路径上黑色结点数大于x到其右子树叶到叶节点的路径上黑色节点数。违反性质5,所以节点y为红色。

由于y为红色,如果y的子树存在,依据性质4能够得出y的两棵子树必为黑色。从x到经过y到各叶节点的路径上的黑色节点数大于到右子树叶节点路径上的黑色节点数。

同上所述,当y为x的右孩子时也能够证明结论2


以下讨论红黑树的删除问题:

1. 从上面的两个结论能够看出。假设要删除的节点仅仅有一个孩子,那么直接用孩子节点的值取代父节点的值。删除子节点就能够。不须要进入删除调整算法。

2. 若当前要删除的节点两个孩子都不为空,此时我们仅仅须要找到当前节点中序序列的后继节点。用后继节点的值替换当前节点的值。

将后继节点作为新的当前节点,此时的当前节点一定仅仅有一个右孩子或左右孩子都为空。

3. 通过步骤2后假设当前节点有后继节点,直接用其后继节点值替换当前节点值,不须要进入删除调整算法。

假设当前节点没有后继节点。进入删除调整算法。

算法流程步骤:

1.      推断x的左右子树是否为空。

2.      假设x的左右子都不为空。找到中序序列中x的后继节点y,将x的值用y取代。将y作为新的x节点转到步骤1。否则转步骤3

3.      假设x的左子不空,将x的值用左子的值取代,删除x的左子,算法结束。否则转4

假设x的右子不空,将x的值用右子的值取代。

4.      假设x的右子不空,将x的值用右子的值取代,删除x的右子,算法结束。否则转5

5.      删除x。进入到红黑树删除节点调整程序。

以下通过图来具体解释红黑树的删除过程

首先利用上篇文章中的代码生成一棵红黑树,插入的顺序为:14,9,41。39。47,20,15,22。7。3,28,24

                                                                           图1:红黑树

1.删除节点22,因为节点22仅仅有一个孩子24。所以直接把22替换成24。依据上面的结论,不须要进行删除调整算法。

                                                                  图2:删除节点22

2.删除节点24。24的节点颜色为黑色,且其兄弟39节点也为黑色,39的两个孩子为空,也为黑,所以将39结点染红,父节点28作为新的当前节点。因为28是红色,所以将28染黑,算法结束。

                                                       图3:删除节点24后的红黑树

3.删除节点39,由于39为叶节点,颜色为红。直接删除。不须要作不论什么调整。

     

                                                                   图4:删除节点39后的红黑树

4.删除节点28,因为节点28是黑色。其兄弟节点47为黑,兄弟节点的两孩子也为黑。所以节点47染红。

父节点41变当前节点


                                                     图5:删除节点28第一次调整

如今41为当前节点,因为41的兄弟节点14为黑,14的两个孩子也为黑。所以将14节点染红。父节点20也就是根节点为当前节点

                                                    图6:删除节点28第二次调整

此时20为当前节点,因为20是根节点调整算法结束。将28从红黑树中删除。

                                                             图7:删除节点28后的红黑树

至此红黑树的属性所有恢复

以下给出删除红黑树节点及调整的c++代码。

关于红黑树删除调整算法能够看July的博客,他说的比較具体。

这个代码是在上一篇 stl map底层之红黑树插入步骤具体解释与代码实现基础上添加的新功能

删除节点的c++程序。

template<typename T>
void RBTree<T>::DeleteValue(const T &v1)
{
	RBNode<T>		*p = NULL;
	RBNode<T>		*nextNode = NULL;
	Search(v1,p);
	if(p==NULL)
	{
		cout<<"删除的值不存在"<<endl;
		return;
	}
	if(p->left && p->right)
	{
		RBNode<T> *tempNode = p->right;
		while(tempNode)
		{//中序序列的后继节点
			nextNode = tempNode;
			tempNode = tempNode->left;
		}
		p->val = nextNode->val;
		p = nextNode;
	}
	if(p->left)
	{
		//直接用后继节点的值替换
		RBNode<T> *temp = p->left;
		p->val = temp->val;
		p->left = NULL;
		delete temp;
	}
	else if(p->right)
	{
		//直接用后继节点的值替换
		RBNode<T> *temp = p->right;
		p->val = temp->val;
		p->right = NULL;
		delete temp;
	}
	else
	{
		//左右子树都不存在,须要进入删除调整算法
		DeleteReblance(p);
		if(p==root)
		{
			root = NULL;
		}
		else if(p==p->parent->left)
		{//父节点的指针域须要改动
			p->parent->left = NULL;
		}
		else if(p==p->parent->right)
		{//父节点的指针域须要改动
			p->parent->right = NULL;
		}
		delete p;
	}
}

红黑树删除后调整算法:

template<typename T>
void RBTree<T>::DeleteReblance(RBNode<T> *node)
{
	RBNode<T> *parent = NULL;
	RBNode<T> *other = NULL;
	while(node->color==_rb_black_node && node->parent)
	{
		parent = node->parent;
		if(node == parent->left)
		{
			other = parent->right;
			if(other->color==_rb_red_node)
			{//情形1兄弟节点为红
				parent->color = _rb_red_node;
				other->color = _rb_black_node;
				_rbtree_rotate_left(parent);
				other = parent->right;
			}
			if( (other->left==NULL || other->left->color==_rb_black_node)
				&& (other->right==NULL || other->left->color==_rb_black_node))
			{//情形2兄弟为黑。且兄弟的两个孩子也为黑
				other->color=_rb_red_node;
				node = parent;
				continue;
			}
			if( other->right==NULL || other->right->color==_rb_black_node)
			{//情形3兄弟节点的右孩子为黑,左为红
				other->left->color=_rb_black_node;//此时左孩子一定存在且颜色为红,假设不满足就不会进入这个条件
				other->color = _rb_red_node;
				_rbtree_rotate_right(other);
				other = parent->right;
			}
			//情形4兄弟节点的右孩子为红
			other->right->color=_rb_black_node;
			other->color = parent->color;
			parent->color = _rb_black_node;
			_rbtree_rotate_left(parent);
			break;
		}
		else
		{
			other = parent->left;
			if(other->color==_rb_red_node)
			{//情形1兄弟节点为红
				parent->color = _rb_red_node;
				other->color = _rb_black_node;
				_rbtree_rotate_right(parent);
				other = parent->left;
			}
			if( (other->left==NULL || other->left->color==_rb_black_node)
				&& (other->right==NULL || other->left->color==_rb_black_node))
			{//情形2兄弟为黑,且兄弟的两个孩子也为黑
				other->color=_rb_red_node;
				node = parent;
				continue;
			}
			if( other->left==NULL || other->left->color==_rb_black_node)
			{//情形3兄弟节点的右孩子为黑,左为红
				other->right->color=_rb_black_node;//此时左孩子一定存在且颜色为红。假设不满足就不会进入这个条件
				other->color = _rb_red_node;
				_rbtree_rotate_left(other);
				other = parent->left;
			}
			//情形4兄弟节点的右孩子为红
			other->left->color=_rb_black_node;
			other->color = parent->color;
			parent->color = _rb_black_node;
			_rbtree_rotate_right(parent);
			break;
		}
	}
	node->color = _rb_black_node;
}