红黑树--删除(自顶向下)

本文详细介绍了红黑树的删除过程及其调整算法。通过具体的步骤和案例,解释了如何在保持红黑树性质的同时完成节点的删除操作。适用于对红黑树有一定了解并希望深入学习其删除机制的读者。

删除过程

在不涉及调整时,类似于AVL树的调整,先寻找要删除的节点,再寻找替换他的节点,将其替换,而后删除替换的叶子节点。
下面我们先来看一下删除调整函数。前提是当前节点为黑色,进入删除调整函数(eraseAdjust)

删除调整的流程

变量定义

在这里插入图片描述

调整流程

在这里插入图片描述

第一步:

在这里插入图片描述上图为右右型(父节点是祖父节点的右孩子,当前节点是父节点的右孩子,通过定义的变量left 和 childleft的真假判断)一共为四种类型,左左,左右,右左,右右类型。
左左类型、右左类型—>左旋(传入当前节点的父节点)
右右类型、左右类型–>右旋(传入当前节点的父节点)
再将左旋和右旋的返回值赋给祖父节点的左或右孩子(通过left的值)

第二步

在这里插入图片描述特殊情况处理,先处理完,剩下的就是需要处理的一般情况。

第三步

在这里插入图片描述
有红孩子分为六种情况,如下图:
在这里插入图片描述

第四步

判断属于那种类型,此时可以确定的是:1.当前节点为黑色,2.前节点的孩子都为黑色 3.当前节点的兄弟节点为黑色
根据当前接待你兄弟节点的孩子颜色分类,分为四类如下图:
在这里插入图片描述

LBr0

兄弟节点的孩子都为黑色,分为左右两种情况,统一处理
在这里插入图片描述

LBr1.1

兄弟节点有一个红孩子。通俗来讲,就是当前节点的外侄子(兄弟节点的远孩子)如下图

在这里插入图片描述在这里插入图片描述

LBr1.2

兄弟节点有一个红孩子,通俗讲是,内侄子(兄弟节点的近孩子)为红色

在这里插入图片描述在这里插入图片描述

LBR2

兄弟节点有两个红孩子
在这里插入图片描述
在这里插入图片描述

到调整函数结束,经过调整之后,节点要么是红色,要么是黑色有一个红孩子

template<class K, class E>
void brTree<K,E>::eraseAdjust(brTreeNode<K,E> *gp,brTreeNode<K,E> *pp,brTreeNode<K,E> *p){
	bool left;//判断当前结点父节点是左孩子还是右孩子
	bool childLeft;//判断当前结点是左孩子还是右孩子
	childLeft=p->element.first<pp->element.first?true:false;//判断当前结点是左孩子还是右孩子
	//判断父节点是祖父节点的左孩子还是右孩子
	left=pp->element.first <  gp->element.first?true:false;
	//判断父节点的颜色,若为黑色,父节点有红孩子发生暂缓,需要调整
	if(pp->color=='b')
	{
		if(left){
			gp->leftChild=childLeft?left_rotations(pp):right_rotations(pp);
			gp->leftChild->color='b';
		}
		else{
			gp->rightChild=childLeft?left_rotations(pp):right_rotations(pp);
			gp->rightChild->color='b';

		}

		pp->color='r';
	}
	//父节点为头节点,孩子节点都为黑色,调整颜色
	if(pp==root&&p->leftChild->color=='b'&&p->rightChild->color=='b')
		{
			p->color='r';
			return;
		}


		//有红孩子,发生暂缓
		if(p->leftChild->color=='r'||p->rightChild->color=='r')
					return;

		else{

				if(childLeft)
				{
					if(pp->rightChild->rightChild->color=='b')
					{	//情况1.1
						if(pp->rightChild->leftChild->color=='b')
						{
							pp->rightChild->color='r';
						}
						//情况3.1
						if(pp->rightChild->leftChild->color=='r')
						{
							pp->rightChild=right_rotations(pp->rightChild);
							if(left)
								gp->leftChild=left_rotations(pp);
							else
								gp->rightChild=left_rotations(pp);
						}
					}

					//2.1   4.1
					else{

						if(left)
						{
							gp->leftChild=left_rotations(pp);
							gp->leftChild->color='r';
							gp->leftChild->rightChild->color='b';
						}
						else
						{
							gp->rightChild=left_rotations(pp);
							gp->rightChild->color='r';
							gp->rightChild->rightChild->color='b';


						}

					}
					pp->color='b';
					p->color='r';

				}
				else{
					if(pp->leftChild->leftChild->color=='b')
					{	//情况1.2
						if(pp->leftChild->rightChild->color=='b')
						{
							pp->leftChild->color='r';
						}
						//情况3.2
						if(pp->leftChild->rightChild->color=='r')
						{
							pp->leftChild=left_rotations(pp->leftChild);
							if(left)
								gp->leftChild=right_rotations(pp);
							else
								gp->rightChild=right_rotations(pp);
						}
					}
					//2.2   4.2
					else{
						if(left)
						{
							if(gp==root)
								gp=gp->rightChild;
							gp->leftChild=right_rotations(pp);
							gp->leftChild->color='r';
							gp->leftChild->leftChild->color='b';
						}
						else{
							if(gp==root)
								gp=gp->rightChild;
							gp->rightChild=right_rotations(pp);
							gp->rightChild->color='r';
							gp->rightChild->leftChild->color='b';}
						}
					pp->color='b';
					p->color='r';
				}

	}
}



删除过程

具体过程:边寻找待删除节点边往下走,遇见黑色节点则调用调整函数,把当前节点调整为红色,若有替换节点则类似边寻找替换节点边调整黑色。
从上到下,找到要删除的点,为当前节点p。
···p有左孩子,在p的左孩子中找到最大的节点s,来替换当前的节点的值,将删除当前节点转换为删除s,此时s要么是红色叶子节点,要么是有一个左红孩子的黑色结点。
···若左边没有替换节点,则判断右孩子的情况,若有右孩子(肯定是红色节点),用右边替换节点s的值替换P节点,删除s.若没有右孩子,则该节点p就是一个待删除的红色叶子节点,直接删掉即可。

//自顶而下的删除
template<class K, class E>
void brTree<K,E>::erase(const K& theKey){
	brTreeNode<K,E> *p = root->rightChild,*pp = root,*gp=&nullNode;
	while(p != &nullNode && p->element.first != theKey){//注意两个句子位置不能颠倒
		if(p->color=='b'){
			eraseAdjust(gp,pp,p);
		}
			gp=pp;
		   pp = p;   // move to a child of p
		   if (theKey < p->element.first)
		      p = p->leftChild;
		   else
		      p = p->rightChild;
		   }//找到了删除的节点
		if (p == &nullNode)//没找到
		{
			return;
		}
		if(p->color=='b'){
			eraseAdjust(gp,pp,p);
		}
		if (p->leftChild !=& nullNode){
			brTreeNode<K,E>*s = p->leftChild,*ps = p,*gs=pp;//初始定义祖父,父节点
		      while (s->rightChild != &nullNode){//寻找替换节点
		    	  if(s->color=='b')
		    		  eraseAdjust(gs,ps,s);
		    	  gs=ps;
		         ps = s;
		         s = s->rightChild;
		      }
		      p->element.first=s->element.first;
		      p->element.second=s->element.second;
		      //删除红色
		      if(s->color=='r'){
		    	  delete s;
		      if(ps==p)
					ps->leftChild=&nullNode;
		      else
					ps->rightChild=s->leftChild;
		      }
		      //2删除黑色(有一个红色的左孩子)
		      else{
		    	  if(ps==p)
		    		  {ps->leftChild=s->leftChild;
					  ps->leftChild->color='b';
					  }
		    	  else
				  {ps->rightChild=s->leftChild;
				  ps->rightChild->color='b';
				  }
		    	  delete s;
		      }
		}
		else{
			if(p->color=='b')
			{
				if(p->element.first>pp->element.first)
							{
								p->rightChild->color='b';
								pp->rightChild=p->rightChild;
								}
							else
							{
								pp->leftChild=p->rightChild;
								pp->leftChild->color='b';
							}
			}
			else
			{
				if(p->element.first>pp->element.first)
					pp->rightChild=&nullNode;
				else
					pp->leftChild=&nullNode;
			}
			delete p;
		}
}

删除示例

1、删除90
在这里插入图片描述
在这里插入图片描述
2、删除80

在这里插入图片描述
3、删除70
在这里插入图片描述4、删除65
在这里插入图片描述
红黑树的插入及一些基础函数请见https://blog.youkuaiyun.com/weixin_41533852/article/details/96877592

over!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值