红黑树RBT基本概念与实现

本文介绍了红黑树的基本概念,它作为一种优化的平衡二叉搜索树,确保查找效率。文章详细阐述了红黑树的性质,如根节点为黑色、红色节点不能相邻等,并探讨了在红黑树中添加节点的过程,说明了添加的节点默认为红色的原因。此外,还提及了节点删除的操作,讨论了在删除操作中如何维护红黑树的平衡。

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

1. 基本概念

RBT的作用与平衡二叉树类似,目的是优化原始BST查找效率低的问题。RBT需成立,要满足如下条件:

  • 树中每个节点有颜色(红或黑)
  • 根节点必须为黑色
  • NULL值处称为终端节点,我们可以认为是黑色
  • 不允许两个红节点互为父子关系
  • 从任意节点向下出发,到所有终端节点的各条路径上黑节点个数相同

2. RBT节点添加

向RBT添加节点,该节点默认初始化为红色。(若为黑色则第五个条件不满足,若为红色可能不满足第四个条件,但第五个条件不好调控,所以选择红色。)
添加步骤如下图:
在这里插入图片描述

3. RBT节点删除

在这里插入图片描述
代码实现:

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

enum COLOR{RED,BLACK};

typedef struct rbt
{
	int nValue;
	int nColor;
	struct rbt *pLeft;
	struct rbt *pRight;
	struct rbt *pFather;
}RBT;

RBT *pRBT = NULL;

void RightRotate(RBT **pTree)
{
	if(*pTree == NULL || (*pTree)->pLeft == NULL)return;

	RBT *pNode = *pTree;
	RBT *pMark = pNode->pLeft;

	//三个孩子关系
	pNode->pLeft = pMark->pRight;
	pMark->pRight = pNode;
	if(pNode->pFather != NULL)
	{
		if(pNode == pNode->pFather->pLeft)
		{
			pNode->pFather->pLeft = pMark;
		}
		else
		{
			pNode->pFather->pRight = pMark;
		}
	}
	else
	{
		//换根
		pRBT = pMark;
	}

	//三个父亲关系
	if(pNode->pLeft != NULL)
	{
		pNode->pLeft->pFather = pNode;
	}

	pMark->pFather = pNode->pFather;
	pNode->pFather = pMark;
}
void LeftRotate(RBT **pTree)
{
	if(*pTree == NULL || (*pTree)->pRight == NULL)return;

	RBT *pNode = *pTree;
	RBT *pMark = pNode->pRight;

	//三个孩子关系
	pNode->pRight = pMark->pLeft;
	pMark->pLeft = pNode;
	if(pNode->pFather != NULL)
	{
		if(pNode == pNode->pFather->pLeft)
		{
			pNode->pFather->pLeft = pMark;
		}
		else
		{
			pNode->pFather->pRight = pMark;
		}
	}
	else
	{
		//换根
		pRBT = pMark;
	}

	//三个父亲关系
	if(pNode->pRight != NULL)
	{
		pNode->pRight->pFather = pNode;
	}

	pMark->pFather = pNode->pFather;
	pNode->pFather = pMark;
}

RBT *Search(RBT *pTree,int nNum)
{
	if(pTree == NULL)return NULL;

	while(pTree)
	{
		if(pTree->nValue > nNum)
		{
			//左侧
			if(pTree->pLeft == NULL)
			{
				return pTree;
			}
			pTree = pTree->pLeft;
		}
		else if(pTree->nValue < nNum)
		{
			if(pTree->pRight == NULL)
			{
				return pTree;
			}
			pTree = pTree->pRight;
		}
		else
		{
			printf("data error.\n");
			exit(1);
		}
	}
}

RBT *GetUncle(RBT *pNode)
{
	if(pNode == pNode->pFather->pLeft)
	{
		return pNode->pFather->pRight;
	}
	else
	{
		return pNode->pFather->pLeft;
	}
}

void AddNode(RBT *pTree,int nNum)
{
	//查找
	RBT *pNode = NULL;
	pNode = Search(pTree,nNum);

	//申请空间
	RBT *pTemp = NULL;
	pTemp = (RBT*)malloc(sizeof(RBT));
	pTemp->nValue = nNum;
	pTemp->nColor = RED;
	pTemp->pFather = pNode;
	pTemp->pLeft = NULL;
	pTemp->pRight = NULL;

	//情况分析
	//1.空树
	if(pNode == NULL)
	{
		pRBT = pTemp;
		pRBT->nColor = BLACK;
		return;
	}

	//非空树
	//连接
	if(pTemp->nValue < pNode->nValue)
	{
		pNode->pLeft = pTemp;
	}
	else
	{
		pNode->pRight = pTemp;
	}
	
	//2.父亲是黑的
	if(pNode->nColor == BLACK)
	{
		return;
	}

	//3.父亲是红的
	RBT *pUncle = NULL;
	RBT *pGrandFather = NULL;
	
	while(pNode->nColor == RED)
	{
		pGrandFather = pNode->pFather;
		pUncle = GetUncle(pNode);

		//3.1叔叔是红色
		if(pUncle != NULL && pUncle->nColor == RED)
		{
			pNode->nColor = BLACK;
			pUncle->nColor = BLACK;
			pGrandFather->nColor = RED;

			pTemp = pGrandFather;
			pNode = pTemp->pFather;

			//根
			if(pNode == NULL)
			{
				pRBT->nColor = BLACK;
				break;
			}

			continue;
		}

		//3.2叔叔是黑的
		if(pUncle == NULL || pUncle->nColor == BLACK)
		{
			//3.2.1父亲是爷爷的左
			if(pNode == pGrandFather->pLeft)
			{
				//3.2.1.1当前节点是父亲的右
				if(pTemp == pNode->pRight)
				{
					pTemp = pNode;

					LeftRotate(&pTemp);

					pNode = pTemp->pFather;
				}

				//3.2.1.2当前节点是父亲的左侧
				if(pTemp == pNode->pLeft)
				{
					pNode->nColor = BLACK;
					pGrandFather->nColor = RED;

					RightRotate(&pGrandFather);
					break;
				}
			}

			//3.2.2父亲是爷爷的右
			if(pNode == pGrandFather->pRight)
			{
				//3.2.2.1当前节点是父亲的左
				if(pTemp == pNode->pLeft)
				{
					pTemp = pNode;

					RightRotate(&pTemp);

					pNode = pTemp->pFather;
				}

				//3.2.2.2当前节点是父亲的右
				if(pTemp == pNode->pRight)
				{
					pNode->nColor = BLACK;
					pGrandFather->nColor = RED;

					LeftRotate(&pGrandFather);
					break;
				}
			}
		}
	}
}

void CreateRBT(int arr[],int nLength)
{
	if(arr == NULL || nLength <= 0)return;

	int i;
	for(i = 0;i<nLength;i++)
	{
		AddNode(pRBT,arr[i]);
	}
}

void Traversal(RBT *pTree)
{
	if(pTree == NULL)return;

	printf("val == %d\tcol == %d\n",pTree->nValue,pTree->nColor);

	Traversal(pTree->pLeft);
	Traversal(pTree->pRight);
}

RBT *FindNode(RBT *pTree,int nNum)
{
	if(pTree == NULL)return NULL;

	while(pTree)
	{
		if(pTree->nValue == nNum)
		{
			return pTree;
		}
		else if(pTree->nValue > nNum)
		{
			pTree = pTree->pLeft;
		}
		else
		{
			pTree = pTree->pRight;
		}
	}

	return NULL;
}

void DelNode(RBT *pTree,int nNum)
{
	//查找
	RBT *pTemp = NULL;
	pTemp = FindNode(pTree,nNum);

	if(pTemp == NULL)return;

	//分析孩子情况
	RBT *pMark = NULL;

	if(pTemp->pLeft != NULL && pTemp->pRight != NULL)
	{
		pMark = pTemp;

		pTemp = pTemp->pLeft;
		while(pTemp->pRight != NULL)
		{
			pTemp = pTemp->pRight;
		}

		//值覆盖
		pMark->nValue = pTemp->nValue;
	}

	//颜色
	RBT *pNode = pTemp->pFather;
	//1.根 且无孩子
	if(pNode == NULL && pTemp->pLeft == NULL && pTemp->pRight == NULL)
	{
		pRBT = NULL;
		free(pTemp);
		pTemp = NULL;
		return;
	}

	//2.根 且有一个红孩子
	if(pNode == NULL && (pTemp->pLeft != NULL || pTemp->pRight != NULL))
	{
		pRBT = pTemp->pLeft ? pTemp->pLeft : pTemp->pRight;
		pRBT->nColor = BLACK;
		pRBT->pFather = NULL;

		free(pTemp);
		pTemp = NULL;
		return;
	}

	//3.非根 红色 
	if(pTemp->nColor == RED)
	{
		if(pTemp == pNode->pLeft)
		{
			pNode->pLeft = NULL;
		}
		else
		{
			pNode->pRight = NULL;
		}
		free(pTemp);
		pTemp = NULL;
		return;
	}

	//4.非根 黑色 且有一个红孩子
	if(pTemp->nColor == BLACK && (pTemp->pLeft != NULL || pTemp->pRight != NULL))
	{
		if(pTemp == pNode->pLeft)
		{
			pNode->pLeft = pTemp->pLeft ? pTemp->pLeft:pTemp->pRight;
			pNode->pLeft->pFather = pNode;
			pNode->pLeft->nColor = BLACK;
		}
		else
		{
			pNode->pRight = pTemp->pLeft ? pTemp->pLeft:pTemp->pRight;
			pNode->pRight->pFather = pNode;
			pNode->pRight->nColor = BLACK;
		}

		free(pTemp);
		pTemp = NULL;
		return;
	}

	//5.非根 黑 且无孩子
	RBT *pBrother = GetUncle(pTemp);
	
	//假删除
	if(pTemp == pNode->pLeft)
	{
		pNode->pLeft = NULL;
	}
	else
	{
		pNode->pRight = NULL;
	}

	pMark = pTemp;

	while(1)
	{
		//5.1兄弟是红的
		if(pBrother->nColor == RED)
		{
			pBrother->nColor = BLACK;
			pNode->nColor = RED;

			//5.1.1兄弟是父亲的左
			if(pBrother == pNode->pLeft)
			{
				RightRotate(&pNode);
				pBrother = pNode->pLeft;
				continue;
			}

			//5.1.2兄弟是父亲的右
			if(pBrother == pNode->pRight)
			{
				LeftRotate(&pNode);
				pBrother = pNode->pRight;
				continue;
			}
		}

		//5.2兄弟是黑的
		if(pBrother->nColor == BLACK)
		{
			//5.2.1两个侄子全黑
			if((pBrother->pLeft == NULL && pBrother->pRight == NULL)||
				((pBrother->pLeft != NULL && pBrother->pLeft->nColor == BLACK)&&
				(pBrother->pRight != NULL && pBrother->pRight->nColor == BLACK)))
			{
				//5.2.1.1父亲是红的
				if(pNode->nColor == RED)
				{
					pNode->nColor = BLACK;
					pBrother->nColor = RED;
					break;
				}

				//5.2.1.2父亲是黑色的
				if(pNode->nColor == BLACK)
				{
					pBrother->nColor = RED;

					pTemp = pNode;
					pNode = pTemp->pFather;

					//根
					if(pNode == NULL)
					{
						break;
					}
					pBrother = GetUncle(pTemp);
					continue;
				}
			}

			//5.2.2左侄子红,右侄子黑
			if((pBrother->pLeft != NULL && pBrother->pLeft->nColor == RED)&&
				(pBrother->pRight == NULL || pBrother->pRight->nColor == BLACK))
			{
				//5.2.2.1兄弟是父亲的右
				if(pBrother == pNode->pRight)
				{
					pBrother->nColor = RED;
					pBrother->pLeft->nColor = BLACK;

					RightRotate(&pBrother);
					pBrother = pNode->pRight;
					continue;
				}

				//5.2.2.2兄弟是父亲的左
				if(pBrother == pNode->pLeft)
				{
					pBrother->nColor = pNode->nColor;
					pNode->nColor = BLACK;
					pBrother->pLeft->nColor = BLACK;

					RightRotate(&pNode);
					break;
				}
			}

			//5.2.3右侄子是红
			if(pBrother->pRight != NULL && pBrother->pRight->nColor == RED)
			{
				//5.2.3.1兄弟是父亲的左
				if(pBrother == pNode->pLeft)
				{
					pBrother->nColor = RED;
					pBrother->pRight->nColor = BLACK;

					LeftRotate(&pBrother);
					pBrother = pNode->pLeft;
					continue;
				}

				//5.2.3.2兄弟是父亲的右
				if(pBrother == pNode->pRight)
				{
					pBrother->nColor = pNode->nColor;
					pNode->nColor = BLACK;
					pBrother->pRight->nColor = BLACK;

					LeftRotate(&pNode);
					break;
				}
			}
		}
	}
	free(pMark);
	pMark = NULL;
}

int main()
{
	int arr[] = {11,2,14,1,7,15,5,8};
	CreateRBT(arr,sizeof(arr)/sizeof(arr[0]));
	Traversal(pRBT);
	printf("---------------------------\n");
	//AddNode(pRBT,4);
	//Traversal(pRBT);
	DelNode(pRBT,1);
	Traversal(pRBT);
	printf("---------------------------\n");
	DelNode(pRBT,11);
	Traversal(pRBT);
	printf("---------------------------\n");
	DelNode(pRBT,15);
	Traversal(pRBT);
	printf("---------------------------\n");
	DelNode(pRBT,2);
	Traversal(pRBT);
	printf("---------------------------\n");

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值