数据结构:红黑树_性质&添加&删除

本文详细解析红黑树的添加与删除操作流程,包括红黑树的性质、添加时的颜色调整策略及旋转处理,以及删除过程中的颜色与结构调整,确保树的平衡与红黑性质。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

红黑树

一、性质:

1.红黑树的节点颜色不是红就是黑

2.红黑树的根节点一定是黑色的

3.终端节点(叶子节点为空的左右子树)是黑的

4.没有两个红节点为父子关系

5.从任意节点出发到达各各终端节点,各条路径上黑节点的数目必须是完全相同的

二、添加操作流程:

    一、先按左大右小的规律找到对应的添加位置
    二、进行颜色调整
    1.树为空
           节点为黑  以此为根 return
    2.父为黑
          return
    3.父为红 
        3.1叔为红
            父变黑 叔变黑  爷变红 爷为新节点向上调整
            同时,如爷为根 return
        3.2叔为黑
            3.2.1父为爷左
                3.2.1.1z为父右
                    以父为新节点 并以此为支点 左旋
                3.2.1.2z为父左
                    父为黑 爷为红
                    以爷为支点右旋 return
            3.2.2父为爷右
                3.2.2.1z为父左
                    以父为新节点 右旋
                3.2.2.2z为父右
                    父为黑 爷为红
                    以爷为支点左旋  return     

代码:

//这里涉及到 树的旋转 问题,大家可以参考我之前写的博客

https://blog.youkuaiyun.com/Water_st/article/details/99223178


void RBTADD(int num)
{
	//创建新节点
	BinaryTree* pNode = new BinaryTree;
	pNode->colour = RED;
	pNode->n_value = num;
	pNode->pFather = NULL;
	pNode->pLeft = NULL;
	pNode->pRight= NULL;

	BinaryTree* pRoot = pRBT;

	//1.树空
	if(pRoot == NULL)
	{
		pNode->colour = BLACK;
		pRBT = pNode;
		return ;
	}
	//找到合适的插入位置

	while(1)
	{
		if(pNode->n_value > pRoot->n_value)
		{
			if(pRoot->pRight == NULL)
			{
				pRoot->pRight = pNode;
				pNode->pFather = pRoot;
				break;
			}
			pRoot = pRoot->pRight;
		}
		else if(pNode->n_value < pRoot->n_value)
		{
			if(pRoot->pLeft == NULL)
			{
				pRoot->pLeft = pNode;
				pNode->pFather = pRoot;
				break;
			}
			pRoot = pRoot->pLeft;
		}
		else
			throw("插入位置不存在");
	}
	
	//找到插入位置后进行 结点的调整

	BinaryTree* pUncle = NULL;
	BinaryTree* pGrand = NULL;
	BinaryTree* pFather = NULL;
	
	while(1)
	{	
		//2.父 黑
		if(pNode->pFather->colour == BLACK)
			return ;	
		
		pFather = pNode->pFather;
		pUncle = GetUncle(pFather);
		pGrand = pFather->pFather;
	//3.父红
		//3.1叔红
		if(pUncle->colour == RED)
		{
			pUncle->colour = BLACK;
			pFather->colour = BLACK;
			pGrand->colour = RED;

			pNode = pGrand;
			if(pGrand->pFather == NULL)//根节点
			{
				pGrand->colour = BLACK;
				break;
			}
			continue;
		}
		//3.2叔黑
		if(pUncle->colour == BLACK || pUncle == NULL)
		{//3.2.1父是爷左
			if(pFather == pGrand->pLeft)
			{
				//3.2.1.1z是父的右
				if(pNode == pFather->pRight)
				{
					pNode = pFather;
					LeftRoate(&pNode);
					continue;
				}//3.2.1.2z是父的左
				if(pNode == pFather->pLeft)
				{
					 pFather->colour = BLACK;
					 pGrand->colour = RED;
					 RightRoate(&pGrand);
					 break;
				}
			}
		//3.2.2父是爷的右
			if(pFather == pGrand->pRight)
			{
				//3.2.2.1z是父的左
				if(pNode == pFather->pLeft)
				{
					pNode = pFather;
					RightRoate(&pNode);
					continue;
				}//3.2.2.2z是父的右
				if(pNode == pFather->pRight)
				{
					pFather->colour = BLACK;
					pGrand->colour = RED;
					LeftRoate(&pGrand);
					break;
				}
			}
		}
	}
}

三、删除操作流程:

//2019/8/16 不好意思,拖更了

一、找到被删除位置:

二、根据BST性质 找左的最右 或 右的最左 来替换被删除的值

三、根据颜色进行调整
        1.根 没有孩子  直接删除
        2.根 有一个孩子 孩子变黑为新根 删原根
        3.节点为红  直接删除
        4.黑 非根 有一个红孩子  将此孩子子变黑  与爷爷相连 删除父亲
        (假删除)//将被替换节点进行删除
        5.黑 非根 没有孩子
            5.1兄弟为红
                父变红 兄变黑
                5.1.1兄为右
                以父为支点左旋
                兄 = 兄->左
                continue;
                5.1.2兄为左
                以父为支点右旋
                兄 = 兄->右
                continue;
            5.2兄为黑
                5.2.1两个侄子为黑
                    5.2.1.1父为红
                    兄变红 父为黑 return
                    5.2.1.2父为黑
                    兄变红 以父为新节点 更新 父 
                    判断父是否为空(根)return
                    更新 兄
                    continue;
                5.2.2左侄红右侄黑
                    5.2.2.1兄为右
                    兄为红 左侄子为黑 以兄为支点右旋
                    更新兄弟 
                    continue;
                    5.2.2.2兄为左
                    父色给兄 父为黑 左侄子为黑
                    以父为支点右旋
                    return
                5.2.3右侄子为红
                    5.2.3.1兄为左
                    兄为红 右侄子为黑 
                    以兄支点左旋
                    更新兄弟
                    continue
                    5.2.3.2兄为右
                    父色给兄 父为黑 右侄子为黑
                    以父为支点左旋
                    reutrn

void RBTDEL(int num)
{
	BinaryTree* pTemp = pRBT;

	//一`先找到这个节点
	while(pTemp)
	{
		if(pTemp->n_value == num)
		{
			break;
		}
		else if(pTemp->n_value > num)
		{
			pTemp = pTemp->pLeft;
		}else if(pTemp->n_value < num)
		{
			pTemp = pTemp->pRight;
		}
	}
	if(pTemp == NULL)
		return ;
	//二`找到他的替代节点
	BinaryTree* pMark = NULL;
 
 
	if(pTemp->pLeft != NULL && pTemp->pRight != NULL)//有2个孩子
	{
		pMark = pTemp;
		pTemp = pTemp->pLeft;
		while(pTemp->pRight != NULL   )
		{
			pTemp = pTemp->pRight;
		}
		pMark->n_value = pTemp->n_value;
	} 
		 
	 
	//三`颜色分析
	 

		if(pTemp == pRBT)
		{////1。根节点没孩子
			if(!pTemp->pLeft  && !pTemp->pRight)
			{
				delete pTemp;
				pTemp = NULL;
				pRBT = NULL;
			}//2.根节点 有一个孩子
			else if(pTemp->pLeft != NULL || pTemp->pRight != NULL)
			{
				pRBT = pTemp->pLeft?pTemp->pLeft:pTemp->pRight;
				pRBT->colour = BLACK;
				delete pTemp;
				pTemp = NULL;
			}
			return ;
		}
		//3.被删除节点为红色
		if(pTemp->colour == RED)
		{
			delete pTemp;
			pTemp = NULL;
			return ;
		}
		
		BinaryTree* pNode = pTemp->pFather;
		BinaryTree* pBrother = GetUncle(pTemp);
		while(1)
		{
			//4.黑 非根 有一个红孩子
			if(pTemp->pFather != NULL && pTemp->colour == BLACK)
			{
				if(pTemp->pLeft !=NULL || pTemp->pRight != NULL)
				{
					BinaryTree* pDl = pTemp;
					pTemp = pTemp->pLeft?pTemp->pLeft:pTemp->pRight;
					pTemp->colour = BLACK;
					if(pDl == pTemp->pLeft)
					{
						pNode->pLeft = pTemp;
					}else
					{
						pNode->pRight = pTemp;
					}
					delete pDl;
					pDl = NULL;
					return ;
				}
			}
			//假删除
			if(pTemp == pNode->pLeft)
				pNode->pLeft = NULL;
			else if(pTemp == pNode->pRight)
				pNode->pRight = NULL;


			//5.如果黑 没有孩子
			if(pTemp->pLeft == NULL && pTemp->pRight == NULL)
			{
				//5.1兄 为红
				if(pBrother->colour == RED)
				{
				//兄为黑 父为红
					pBrother->colour = BLACK;
					pNode->colour = RED;
					//5.1.1节点为 父左
					if(pNode->pLeft == pTemp )
					{
						LeftRoate(&pNode);
						pBrother = pBrother->pLeft;
						continue;
					}//5.1.2 节点为父右
					if(pTemp = pTemp->pRight)
					{
						RightRoate(&pNode);
						pBrother = pBrother->pRight;
						continue;
					}		
				}
				//5.2兄为黑
				if(pBrother->colour == BLACK)
				{
					//5.2.1 左右侄子为黑
					if(pBrother->pLeft == NULL&&pBrother->pRight==NULL||
						(pBrother->pLeft!= NULL && pBrother->pLeft->colour == BLACK )&&
						(pBrother->pRight!= NULL &&pBrother->pRight->colour == BLACK)
					 )
					{//5.2.1.1如果父亲为红
						if(pNode->colour == RED)
						{
							pBrother->colour = RED;
							pNode->colour = BLACK;
							return ;
						}//5.2.1.2如果父亲为黑
						if(pNode->colour == BLACK)
						{//兄红 父为新节点向上调整 更新父 兄 
							pBrother->colour = RED;
							pTemp = pNode;
							pNode = pTemp->pFather;
							if(pNode == NULL)
								return ;
							pBrother = GetUncle(pTemp);
						}
					}
					//5.2左侄子为红 右侄子黑
					if((pBrother->pLeft!=NULL && pBrother->pLeft->colour == RED) &&
						(!pBrother->pRight||pBrother->pRight->colour == BLACK))
					{
						//5.2.1兄为右
						if(pNode->pRight == pBrother)
						{
							pBrother->colour = RED;
							pBrother->pLeft->colour = BLACK;
							RightRoate(&pBrother);
							pBrother = pNode->pRight;
							continue;
						}
						//5.2.2兄为左
						if(pNode->pLeft == pBrother)
						{
							pBrother->colour = pNode->colour;
							pNode->colour = BLACK;
							pBrother->pLeft->colour = BLACK;
							RightRoate(&pNode);
							return ;
						}
					}
					if(pBrother->pRight != NULL || pBrother->pRight->colour == BLACK)
					{
						//5.2.3右侄子红
						//5.2.3.1兄为左
						if(pBrother == pNode->pLeft)
						{
							pBrother->colour = RED;
							pBrother->pRight->colour = BLACK;
							LeftRoate(&pBrother);
							pBrother = pNode->pLeft;
							continue;
						}
						else//5.2.3.1兄为右
						{
							pBrother->colour = pNode->colour;
							pNode->colour = BLACK;
							pNode->pRight->colour = BLACK;
							LeftRoate(&pNode);
							return ;
						}
					}
				}
			}				
		}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值