【数据结构】C语言实现红黑树的性质如何调平以及红黑树的添加(C语言实现)

什么是红黑树
红黑树是一种被广泛应用的平衡二叉搜索树。
为了解决BST的不平衡的问题。
它不仅是一个二叉搜索树,还具有以下几个特点:
1.每个节点非红即黑。
2.红黑树的根节点必须是黑色的。
3.叶子下的空节点是哨兵节点,其颜色是黑色。
4.红黑树不允许两个红节点为父子关系。
5.红黑树从任意节点向下出发,其所有能达到各个终端节点的路径上,黑节点的数目必须相同。

以上的几点,确定的红黑树添加规则。

并且,红黑树不会右任意一条路径的长度为其他路径长度的2倍。

添加的情况分析:

设新添加的节点为Z。
1.空树

新来的节点为根,并且将颜色变为黑色。

2.父亲是黑色的
直接将Z放入。

3.父亲为红色的(这种情况下,爷爷 一定是黑色的)
在这种情况下,我们需要的到叔叔的颜色。

3.1叔叔是红色的
将叔叔和父亲的节点颜色变为黑色,爷爷的颜色改为红色,爷爷为新的Z,继续向上讨论。

3.2叔叔为黑色
因为叔叔和父亲的颜色不平等,只能旋转调
3.2.1父亲是爷爷的左
3.2.1.1 Z是父亲的右
即<
父亲是新的Z,以Z为支点左旋。

3.2.1.2 Z是父亲的右
将父亲变为黑色,爷爷变为红色,
以爷爷为支点,右旋。

3.2.2 父亲是爷爷的右
3.2.2.1 Z是父亲的左
即>
父亲是新的Z,以Z为支点右旋。

3.2.2.2 Z是父亲的右
父亲变为黑色,爷爷变为红色,以爷爷为支点左旋。

代码如下:

#include<stdio.h>
#include<stdlib.h>
enum COLOR {RED,BLACK}typedef struct rbt
{
	int nValue;
	int nColor;
	rbt*pLeft;
	rbt*pRight;
	rbt*pFather;
}RBT;
RBT*pRBT = NULL;

void RightRotate(RBT*pTree)
{
	if(*pTree == NULL || pTree->pLeft == NULL)
	return ;
	RBT*pNode = *pTree;
	RBT*pMark = pTree->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 || nNum <= 0)
		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->pRight;
			
			pTree = pTree->pRight;
		}
		else
		{
			printf("data error.");
		}
	}
}

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->nColor = RED;
	pTemp->nValue = nNum;
	pTemp->pLeft = NULL;
	pTemp->pRight = NULL;
	pTemp-.pFather = pNode;
	
	//情况分析
	//1.空树
	if(pNode == NULL)
	{
		pNode = pTemp;
		pNode->nColor = BLACK;
		return;
	}
	//非空树
	//连接
	if(pNode->nValue > nNum)
	{
		pNode->pLeft = pTemp;
	}
	else
	{
		pNode->pRight = pTemp;
	}
	//2.父亲是黑色的
	if(pNode->nColor == BLACK)
	{
		return;
	}
	//3.父亲是红的
	RBT*pUncle = NULL;
	RBT*pGrandpa = NULL;
	while(pNode->nColor == RED)
	{
		pGrandpa = pNode->pFather;
		pUncle = GetUncle(pNode);
		
		//3.1叔叔是红色的
		if(pUncle->nColor == RED && pUncle != NULL)
		{
			pNode->nColor = BLACK;
			pUncle->nColor = BLACK;
			pGrandpa->nColor = RED;
			pTemp = pGrandpa;
			pNode = pGrandpa->pFather;
			if(pNode == NULL)
			{
				pRBT->nColor = BLACK;
				break;
			}
			continue;
		}
		//3.2叔叔是黑色的
		if(pUncle->nColor == BLACK || pUncle == NULL)
		{
			//3.2.1父亲是爷爷的左
			if(pNode == pGrandpa->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;
					pGrandpa->nColor = RED;
					RightRotate(&pGrandpa);
					break;
				}
			}
			//3.2.2 父亲是爷爷的右
			if(pNode == pGrandpa->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;
					pGrandpa->nColor = RED;
					LeftRotate(&pGrangpa);
					break;
				}
			}
		}
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值