数据结构:红黑树实现

红黑树的特性:

1.每个结点非红即黑

2.根结点为黑色

3.所有叶子结点为黑色

4.父子不同红

5.任意结点,从该结点到所有子孙结点路径上的黑色结点数量相同

下面请看详细代码(其中包含了注释)(需要用到二叉树旋转请跳转)二叉树的旋转

#include <iostream>
using namespace std;

enum COLOR {RED,BLACK};
struct RBT
{
	int value;
	RBT* pFather;
	RBT* pLeft;
	RBT* pRight;
	COLOR color;
};
RBT* GetFather(RBT* pRoot, int value)
{
	while (pRoot != nullptr)
	{
		if (value < pRoot->value)
		{
			if (pRoot->pLeft == nullptr)
			{
				return pRoot;
			}
			pRoot = pRoot->pLeft;
		}
		else if(value > pRoot->value)
		{
			if (pRoot->pRight == nullptr)
			{
				return pRoot;
			}
			pRoot = pRoot->pRight;
		}
		else
		{
			cout << "数据有误" << endl;
			break;
		}
	}
	return nullptr;
}
RBT* GetUncle(RBT* pRoot)
{	
	if (pRoot == nullptr || pRoot->pFather == nullptr || pRoot->pFather->pFather == nullptr)
	{
		return nullptr;
	}
	if (pRoot->pFather->pFather->pLeft == pRoot->pFather)
	{
		return pRoot->pFather->pFather->pRight;
	}
	else
	{
		return pRoot->pFather->pFather->pLeft;
	}
}
void RightRotate(RBT* pRBT,RBT*& rpRoot)
{
	if (pRBT == nullptr || pRBT->pLeft == nullptr)
	{
		return;
	}
	RBT* pMark = pRBT;
	RBT* pTemp = pRBT->pLeft;

	pMark->pLeft = pTemp->pRight;
	pTemp->pRight = pMark;
	if (pMark->pFather == nullptr)
	{
		rpRoot = pTemp;
	}
	else
	{
		if (pMark->pFather->pLeft == pMark)
		{
			pMark->pFather->pLeft = pTemp;
		}
		else
		{
			pMark->pFather->pRight = pTemp;
		}
	}
	if (pMark->pLeft != nullptr)
	{
		pMark->pLeft->pFather = pMark;
	}
	pTemp->pFather = pMark->pFather;
	pMark->pFather = pTemp;
}
void LeftRotate(RBT* pRBT, RBT*& rpRoot)
{
	if (pRBT == nullptr || pRBT->pRight == nullptr)
	{
		return;
	}
	RBT* pMark = pRBT;
	RBT* pTemp = pRBT->pRight;

	pMark->pRight = pTemp->pLeft;
	pTemp->pLeft = pMark;
	if (pMark->pFather == nullptr)
	{
		rpRoot = pTemp;
	}
	else
	{
		if (pMark->pFather->pLeft == pMark)
		{
			pMark->pFather->pLeft = pTemp;
		}
		else
		{
			pMark->pFather->pRight = pTemp;
		}
	}
	if (pMark->pRight != nullptr)
	{
		pMark->pRight->pFather = pMark;
	}
	pTemp->pFather = pMark->pFather;
	pMark->pFather = pTemp;
}
void AddRBT(RBT*& rpRoot, int value)
{
	//获得父亲
	RBT* pFather = GetFather(rpRoot, value);
	//创建结点
	RBT* pMark = new RBT;
	pMark->value = value;
	pMark->color = RED;
	pMark->pFather = pFather;
	pMark->pLeft = nullptr;
	pMark->pRight = nullptr;

	//判断空树
	if (rpRoot == nullptr)
	{
		//结点为根 变黑
		pMark->color = BLACK;
		rpRoot = pMark;
		return;
	}
	//非空
	//放入
	if (pMark->value < pFather->value)
	{
		pFather->pLeft = pMark;
	}
	else
	{
		pFather->pRight = pMark;
	}
	while (1)
	{
		//判断父亲颜色
		pFather = pMark->pFather;
		//父亲是黑的   结束
		if (pFather->color == BLACK)
		{
			return;
		}
		//父亲是红的
		//判断叔叔颜色
		RBT* pUncle = GetUncle(pMark);
		//叔叔红色
		if (pUncle != nullptr && pUncle->color == RED)
		{
			//父亲和叔叔变黑
			pFather->color = BLACK;
			pUncle->color = BLACK;
			//爷爷变红
			pFather->pFather->color = RED;
			//爷爷为新标记 
			pMark = pFather->pFather;
			//判断新标记是否为根
			if (pMark->pFather == nullptr)
			{
				//爷爷为根 变黑 结束
				pMark->color = BLACK;
				return;
			}
			continue;
		}
	 
		//叔叔是黑的(包含空)
		if (pUncle == nullptr || pUncle->color == BLACK)
		{

			//判断父亲方向
			//父亲是爷爷的左
			if (pFather->pFather->pLeft == pFather)
			{
				//判断标记的方向
				//标记是父亲的右
				if (pMark == pFather->pRight)
				{
					//父亲为新标记
					pMark = pFather;
					//以标记为支点左旋
					LeftRotate(pMark, rpRoot);
				}
				else//标记是父亲的左
				{
					//标记的爷爷变红
					pMark->pFather->pFather->color = RED;
					//标记的父亲变黑
					pMark->pFather->color = BLACK;
					//以标记的爷爷为支点右旋  结束
					RightRotate(pMark->pFather->pFather, rpRoot);
					return;
				}
			}

			//判断父亲方向
			//父亲是爷爷的右
			if (pFather->pFather->pRight == pFather)
			{
				//判断标记的方向
				//标记是父亲的左
				if (pMark == pFather->pLeft)
				{
					//父亲为新标记
					pMark = pFather;
					//以标记为支点右旋
					RightRotate(pMark, rpRoot);
				}
				else//标记是父亲的右
				{
					//标记的爷爷变红
					pMark->pFather->pFather->color = RED;
					//标记的父亲变黑
					pMark->pFather->color = BLACK;
					//以标记的爷爷为支点左旋  结束
					LeftRotate(pMark->pFather->pFather, rpRoot);
					return;
				}
			}
		}
	}
}		

ostream& operator<<(ostream& os, COLOR color)
{
	if (color == RED)
	{
		os << "红";
	}
	else
	{
		os << "黑";
	}
	return os;
}
void InOrder(RBT* pRoot)
{
	if (pRoot == nullptr)
	{
		return;
	}
	InOrder(pRoot->pLeft);
	cout << pRoot->value << "\t" << pRoot->color << endl;
	InOrder(pRoot->pRight);
}

RBT* GetDeleteNode(RBT* pRoot, int value)
{
	while (pRoot != nullptr)
	{
		if (value < pRoot->value)
		{
			pRoot = pRoot->pLeft;
		}
		else if (value > pRoot->value)
		{
			pRoot = pRoot->pRight;
		}
		else
		{
			return pRoot;
		}
	}
	return nullptr;
}

RBT* GetBrother(RBT* pRoot)
{
	if (pRoot == nullptr || pRoot->pFather == nullptr)
	{
		return nullptr;
	}
	return pRoot == pRoot->pFather->pLeft ? pRoot->pFather->pRight : pRoot->pFather->pLeft;
}
void DeleteRBT(RBT* rpRoot, int value)
{
	//找到要删除的结点
	RBT* pDel = GetDeleteNode(rpRoot, value);
	if (pDel == nullptr)
	{
		return;
	}
	//如果删除结点有两个孩子  替换删除结点
	if (pDel->pLeft != nullptr && pDel->pRight != nullptr)
	{
		RBT* pMark = pDel;
		pDel = pDel->pRight;
		while (pDel->pLeft != nullptr)
		{
			pDel = pDel->pLeft;
		}
		pMark->value = pDel->value;
	}

	//根
	if (pDel->pFather == nullptr)
	{
		//判断是否有一个孩子
		if (pDel->pLeft == nullptr && pDel->pRight == nullptr)
		{
			rpRoot = nullptr;
		}
		else
		{
			rpRoot = pDel->pLeft != nullptr ? pDel->pLeft : pDel->pRight;
			rpRoot->color = BLACK;
			rpRoot->pFather = nullptr;
		}

		//删除  新根
		delete pDel;
		pDel = nullptr;
		return;
	}

	RBT* pFather = pDel->pFather;
	//非根
	//分析删除结点颜色
	if (pDel->color == RED)
	{
		//红
		//直接删除
		if (pDel == pFather->pLeft)
		{
			pFather->pLeft = nullptr;
		}
		else
		{
			pFather->pRight = nullptr;
		}
		delete pDel;
		pDel = nullptr;	
		return;
	}
	//黑  判断是否有孩子
	//有孩子  一定是红孩子
	if (pDel->pLeft != nullptr || pDel->pRight != nullptr)
	{
		//红孩子变黑  与爷爷相连  删除标记
		RBT* pChild = pDel->pLeft != nullptr ? pDel->pLeft : pDel->pRight;
		pChild->color = BLACK;
		pChild->pFather = pFather;
		if (pFather->pLeft == pFather)
		{
			pFather->pLeft = pChild;
		}
		else
		{
			pFather->pRight = pChild;
		}
		delete pDel;
		pDel = nullptr;
		return;
	}

	//没有孩子
	//分析兄弟情况
	//先获得兄弟   删除结点
	RBT* pBrother = GetBrother(pDel);
	if (pFather->pLeft == pDel)
	{
		pFather->pLeft = nullptr;
	}
	else
	{
		pFather->pRight = nullptr;
	}

	//调整  loop
	while (1)
	{
		//兄弟为红   父亲变红   兄弟变黑   分析兄弟方向
		if (pBrother->color == RED)
		{
			pFather->color = RED;
			pBrother->color = BLACK;
			//兄弟为父亲的右  以父亲为支点左旋  更换兄弟  兄弟为父亲的右  继续分析
			if (pFather->pRight == pBrother)
			{
				LeftRotate(pFather, rpRoot);
				pBrother = pFather->pRight;
			}
			//兄弟为父亲的左  以父亲为支点右旋  更换兄弟  兄弟为父亲的左  继续分析
			else
			{
				RightRotate(pFather, rpRoot);
				pBrother = pFather->pLeft;
			}
			continue;
		}


		//兄弟为黑   分析两个侄子的颜色
		if (pBrother->color == BLACK)
		{
			//两个侄子全黑(包括全空)  分析父亲颜色
			if ((pBrother->pLeft == nullptr && pBrother->pRight == nullptr) || 
				((pBrother->pLeft != nullptr && pBrother->pLeft->color == BLACK) &&
				 (pBrother->pRight != nullptr && pBrother->pRight->color == BLACK)))
			{
				//父亲为红   父亲变黑   兄弟变红   结束
				if (pFather->color == RED)
				{
					pFather->color = BLACK;
					pBrother->color = RED;
				}
				//父亲为黑   兄弟变红   父亲为新的标记   跟换兄弟   标记为根结束  不为根继续分析
				else
				{
					pBrother->color = RED;
					pDel = pFather;
					if (pDel->pFather == nullptr)
					{
						return;
					}
					continue;
				}
			}
			
			

			//左侄子红右侄子黑(包括空)   分析兄弟方向
			if (pBrother->pLeft != nullptr && pBrother->pLeft->color == RED &&
			   (pBrother->pRight == nullptr || pBrother->color == BLACK))
			{
				//兄弟是父亲的右   兄弟变红  左侄子变黑   以兄弟为支点右旋   更换兄弟   继续分析
				if (pBrother == pFather->pRight)
				{
					pBrother->color = RED;
					pBrother->pLeft->color = BLACK;
					RightRotate(pBrother, rpRoot);
					pBrother = pFather->pRight;
					continue;
				}
				//兄弟是父亲的左   父亲颜色给兄弟   父亲变黑   左侄子变黑   以父亲为支点右旋  结束
				if (pBrother == pFather->pLeft)
				{
					pBrother->color = pFather->color;
					pFather->color = BLACK;
					pBrother->pLeft->color = BLACK;
					RightRotate(pFather, rpRoot);
					return;
				}
			}
			

			//右侄子红   分析兄弟方向
			if (pBrother->pRight != nullptr && pBrother->pRight->color == RED)
			{
				//兄弟是父亲的左   兄弟变红   右侄子变黑   以兄弟为支点左旋   更换兄弟   继续分析
				if (pBrother == pFather->pLeft)
				{
					pBrother->color = RED;
					pBrother->pRight->color = BLACK;
					LeftRotate(pBrother, rpRoot);
					pBrother = pFather->pLeft;
					continue;
				}
				//兄弟是父亲的右   父亲颜色给兄弟   父亲变黑   右侄子变黑   以父亲为支点左旋  结束
				if(pBrother == pFather->pRight)
				{
					pBrother->color = pFather->color;
					pFather->color = BLACK;
					pBrother->pRight->color = BLACK;
					return;
				}
			}
			
			
		}
		 
			
			
	}
	



}

	
int main()
{
	RBT* pRoot = nullptr;

	int arr[] = { 11,2,14,1,7,15,5,8 };

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		AddRBT(pRoot, arr[i]);
	}

	AddRBT(pRoot, 4);

	InOrder(pRoot);
	cout << "----------------------------------" << endl;
	//DeleteRBT(pRoot, 11);
	
	///RBT* pBrother = GetBrother(pRoot->pRight);
	DeleteRBT(pRoot, 4);

	InOrder(pRoot);
	

	


	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值