算法导论---红黑树删除详解

红黑树删除算法详解

删除算法相较于插入要稍微复杂些。

删除操作,首先与二叉树删除一致,找到删除的节点,若是只有左节点或者只有右节点或者没有左右子树,那么删除的节点就是原来的节点,只要将删除节点的父节点指针指向子节点。

2)若是同时有左右子树,利用查找后继,就是找到右子树中最小的元素,然后将找到节点与这个节点的值进行交换,那么删除的就是这个后继节点,这个后继节点是基于中序遍历找出来的。

3)我们找到可以交换的节点,现在只要删除这个节点就好了,现在要判断这个新的删除节点的颜色。(1)如果这个节点是红的,那么很好,经过它的节点黑色并没有改变,红黑树的几个性质也没有受到变化。(2)、找到待删除节点的孩子节点x,很肯定的是待删除节点只有一个子树。也就是说这个x是确定的,那么现在又要分情况来讲。

4)如果待删除节点是黑色的,x是红色的,很好,只要将x的颜色属性置为黑色就好。现在通过x节点的子树上黑色节点又增加了,回到原来的数目。现在还有一种很糟糕的情况是待删除与x节点的颜色属性都是黑色。问题出现了。通过前面的删除操作,通过x节点路径的黑色节点数目减少一个,现在就要对这棵树进行重新的构造。(记住,这个x节点可能下面还有子树)。现在我们针对这种情况分为4种情形来讨论(总的是根据兄弟节点的颜色)

template<class KEY,class VAL>
bool RB_Tree<KEY,VAL>::Delete(KEY key,VAL val)
{
	RB_Node<KEY,VAL> *deleteNode=nullNode;//要删除的节点
	RB_Node<KEY,VAL>*delNodeChild=nullNode;//要删除节点的孩子节点
	RB_Node<KEY,VAL> *index=root;//index为找到的节点
	while(index!=nullNode)
	{
		if(*val<*(index->val))
		{
			index=index->leftNode;
		}
		else if (*val>*(index->val))
		{
			index=index->rightNode;
		}
		else
		{
			break;
		}
	}
	if (index->leftNode==nullNode||index->rightNode==nullNode)//分两种情况,一种是只有左子树或者只有右子树
	{
		deleteNode=index;
	}
	else
	{
		deleteNode=successor(index);//若同时有左右子树,找到后继
//见前面的文章,查找后继节点
     	}
	if(deleteNode->leftNode!=nullNode)
	{
		delNodeChild=deleteNode->leftNode;
	}
	else
	{
		delNodeChild=deleteNode->rightNode;//获知孩子为左子树还是右子树
	}
	delNodeChild->parentNode=deleteNode->parentNode;//将父节点孩子指针指向这个节点的孩子节点
	if (delNodeChild->parentNode==nullNode)
	{
		root=delNodeChild;
	}
	else
	{
		if (deleteNode==deleteNode->parentNode->leftNode)//获取当前节点为父节点的哪个节点
		{
			deleteNode->parentNode->leftNode=delNodeChild;
		}
		else
		{
			deleteNode->parentNode->rightNode=delNodeChild;
		}
	}
	if (deleteNode!=index)
	{
		index->key=deleteNode->key;//交换值
	}
	if (deleteNode->color==BLACK)//若删除的节点为黑色
	{
		DeleteFixup(delNodeChild);//进行树的重新构造
	}
}

template<class KEY,class VAL>
bool RB_Tree<KEY,VAL>::DeleteFixup(RB_Node<KEY,VAL>* delNode)
{
	RB_Node<KEY,VAL>*w;
	while(delNode!=root&&delNode->color==BLACK)
	{
		if (delNode==delNode->parentNode->leftNode)//当前节点为父节点的左子树
		{
			/*1、若兄弟节点为红色。将兄弟节点颜色置为黑色,
				x节点的父节点置为红色,然后将父节点进行左旋。
				此时所做的操作并没有改变什么。通过每个节点的黑色数目依旧没有改变,
				我们只是为了进入下面的3种情况。开始的时候我在想为什么不采用与情形2一样的操作,
				将兄弟节点也置为红色,那么此时每课树的黑色节点数目都减少一个,然后继续回溯。
				但是这个时候我们发现,这样的操作,会使得通过x的黑色节点数目也减少1个,很傻逼的行为*/
			w=delNode->parentNode->rightNode;
			if (w->color==RED)//1.兄弟节点为红色
			{
				delNode->parentNode->color==RED;//将父节点置为红色
				w->color==BLACK;//兄弟节点为黑色
				RotateLeft(delNode->parentNode);
				w=delNode->parentNode->rightNode;//旋转
			}
			else if (w->color==BLACK)
			{
				if(w->leftNode->color==BLACK&&w->rightNode->color==BLACK)//2.兄弟节点极其孩子节点均为黑色
				{
					/*2、若兄弟节点为黑色。将兄弟节点颜色置为红色,
						那么此时通过每个叶子节点的黑色数目是一致的,
						不过未通过x父节点的叶子节点数目反而会比通过的多一个。
						于是我们回溯,继续构造。记住,这个时候如果是从1过来的,
						也就是说父节点是红色的,此时只要将父节点的颜色置为黑色就ok啦。*/
					w->color==RED;
					delNode=delNode->parentNode;
				}

				if (w->color==BLACK&&w->leftNode->color==RED)//3.兄弟节点为黑色,w的左子树为红色
				{
					/*3、若兄弟节点为黑色,且其左子树的颜色为红色,
						将这个左子树颜色置为黑色,w的颜色置为红色,
						进行右旋。为什么这么做呢,只是为了进入4的情况。*/
					w->color==RED;
					w->leftNode->color=BLACK;
					RotateRight(w);
					w=delNode->parentNode->rightNode;
				}
				if(w->leftNode->color==RED&&w->rightNode->color==RED)//4.兄弟节点为黑色,孩子节点均为红色
				{
					/*4、若兄弟节点的左右子树都为红色,且兄弟节点为黑色,
						将w的右子树置为黑色,w的颜色置为x的父节点一样的颜色,
						这个时候父节点的颜色可以为红色也可以为黑色。然后左旋。*/
					w->color==delNode->parentNode->color;
					delNode->parentNode->color=BLACK;
					w->rightNode->color=BLACK;
					RotateLeft(delNode->parentNode);
					delNode=root;//
				}		 
			}
		}
		else if (delNode==delNode->parentNode->rightNode)
		{
			w=delNode->parentNode->leftNode;
			if (w->color==RED)
			{
				delNode->parentNode->color=RED;
				w->color=BLACK;
				RotateRight(delNode->parentNode);
			}
			else if (w->color==BLACK)
			{
				if (w->leftNode->color==BLACK&&w->rightNode->color==BLACK)
				{
					w->color=RED;
					delNode=delNode->parentNode;
				}
				else if (w->rightNode->color==RED&&w->leftNode->color==BLACK)
				{
					w->rightNode->color=BLACK;
					w->color=RED;
					RotateLeft(w);
				}
			    if (w->rightNode==RED&&w->leftNode==RED)
				{
					w->leftNode=BLACK;
					w->color=delNode->color;
					delNode->parentNode=BLACK;
					RotateRight(delNode->parentNode);
				}
			}
		}
	}
	delNode->color=BLACK;
	return true;
}


 

最后我们将x的颜色置为黑色

从上面可以知道我们有两种情况会出循环,一种是兄弟节点与父节点都是红色,只要将父节点的颜色置为黑色。

一种是4的情况,左旋使得通过x的节点黑色节点数目增加一个,达到平衡。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值