ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

还在感觉为红黑树所困扰?相信我你就点进来看!!!★★★

2021-09-12 10:02:42  阅读:186  来源: 互联网

标签:黑树 困扰 pNode color 结点 插入 父亲 进来 pFather


红黑树删除,点击这里!!!

红黑树 :红黑树是一种特殊的二插查找数,不过为了防止二插查找树在最差情况下蜕变成链表,因此红黑树利用了结点的颜色来调节树的平衡,这使得红黑树的任意一条路径长度都不可能超过其他路径的两倍,因此红黑树是一种自调节的高度平衡的二叉查找树。
性质

  • 性质1:结点要么是红要么是黑
  • 性质2:根结点必须是黑色
  • 性质3:每个叶子结点(NIL)是黑色
  • 性质4:每个红色结点的两个子结点一定都是黑色。,不能有两个红色结点相连
  • 性质5:从根结点开始,到这条路径上的空结点,各条路径上的黑色结点个数相同

红黑树的添加操作与删除操作相比,要简单的多,不过比其他数据结构的操作要稍微复杂那么一点,但是如果理解操作的具体过程,也并不是太复杂。我相信,大家跟着我一起,看完这篇文章,一定能掌握红黑树的插入操作!!!

插入情况分析:我们首先来分析一下红黑树的插入情况有哪几种,然后各个击破!!!

对于红黑树插入结点来讲,插入结点时,插入的位置要么是根,要么不是根;插入结点的父亲要么是红色,要么是黑色。总体来看就这几种情况,如下:

按照插入结点的位置情况分

1 插入位置是根
2 插入位置非根

按照插入时的颜色情况分

1 插入结点的父亲是红
2 插入结点的父亲是黑

总体分析插入结点颜色情况

在我们对结点进行插入时,插入的结点颜色应该是红色还是黑色呢?
首先,我们应该知道,在进行插入时,我想总想尽可能的用最少的操作来达到插入结点时红黑树的平衡,这样红黑树的插入效率才会高。因此,如果插入结点是黑色时,由于红黑树要求每条路径上的黑色结点个数相同,当插入结点是黑色时,这条路径上的黑色结点个数就比其他路径上的黑色结点数多一个,要想使得红黑树平衡,我们就需要对整颗红黑树进行调整,显然非常麻烦。而当插入结点是红色时,黑色结点个数不变,只是有可能其父亲结点是红色,这里发生冲突。即使发生冲突,但我们只需要对发生冲突的这里单独进行调整,并不会操作整颗树,因此插入结点是红色的效率要比插入结点是黑色的效率要高!!!

注:红黑树的插入操作,插入结点时,所插入的结点一定是红色结点!!!

如果插入位置处的父结点的颜色是黑色?
此时,我们直接将结点插入即可,因此红色结点并不影响黑色结点个数,也不与红色结点冲突。

如果插入位置处的父结点是红色?
此时,我们也是要直接插入,但是情况要稍微复杂一点,需要进行调整,详细调整过程我们在下面进行讨论,这里先不讨论。
我们想一下,如果插入位置处的父结点是红色,那么其父结点的兄弟(待插入结点的叔叔)可能是红色,也可能是黑色。

详细讨论红黑树结点插入

为了保证每次情况的讨论都是封闭的,即考虑所有的讨论情况,因此我们要互补的进行讨论,即讨论类别为:是/不是,或者为红/黑,这种讨论都是封闭的。
我们已经知道了,对红黑树的结点进行插入时,插入的结点可能是根,也可能不是根。因此,我们需要从插入节点是根和不是根两种情况进行讨论。如果插入的结点是根,那么我们直接将插入节点变黑,根指向插入的结点,结束,如下图(插入6):
在这里插入图片描述

1 插入的结点是根:根指向插入的结点,结点变黑,结束
2 插入的结点不是根

插入的结点是根的时候,情况很简单。那么如果插入的结点不是根呢?对于插入的结点不是根时,就说明插入的结点有父亲,由于父亲结点的颜色关系着我们对红黑树的调整情况。因此我们就需要对插入结点的父亲颜色进行讨论。由于其父亲就可能是红色或者黑色,我们的讨论就分为父亲颜色是黑色和父亲颜色是红色。如果父亲的颜色是黑色,很简单,我们直接将结点插入就行,不需要对红黑树进行调整,应为红色结点不会增加黑色结点的个数(不需要考虑父亲节点是不是根,这里只是针对父结点是黑这种情况,此时插入结点可能是父亲的左,也可能是父亲的右,图片只画出插入结点是父亲的左,插入结点是右时基本一样),如下图(插入6):
在这里插入图片描述

1 插入的结点是根:根指向插入的结点,结点变黑,结束
2 插入的结点不是根

2.1 如果插入结点的父亲是黑结点:链接插入结点,结束
2.2 如果插入结点的父亲是红结点

对于插入结点的父亲结点颜色是黑色时,情况也并不复杂。下面看一下如果插入结点的父亲结点颜色是红色时情况如何。
如果插入结点的父亲结点颜色是红色,那么此时就需要对红黑树进行调整。由于调整可能涉及到旋转,因此我们需要对插入结点是父亲节点的左还是父亲节点的右进行讨论,再进行这个讨论前,我们同样需要判断父亲结点是爷爷结点的左还是右,即如下所示:

1 插入的结点是根:根指向插入的结点,结点变黑,结束
2 插入的结点不是根

2.1 如果插入结点的父亲是黑结点:链接插入结点,结束
2.2 如果插入结点的父亲是红结点

2.2.1如果父亲是爷爷的左

2.2.1.1如果插入结点是父亲的左

2.2.1.1.1如果叔叔的颜色是红:
2.2.1.1.2如果叔叔的颜色是黑:
2.2.1.2如果插入结点是父亲的右

2.2.2如果父亲是爷爷的右

2.2.1.1如果插入结点是父亲的左
2.2.1.2如果插入结点是父亲的右

对于父亲结点颜色为红色时,如果此时父亲是爷爷的左,插入结点是父亲的左,分析如下。如果父亲结点的颜色是红色,那么爷爷结点的颜色一定是黑色。由于插入的结点和父亲的结点颜色都是红色,因此需要进行变色。那么是对插入结点进行变色还是对父亲结点进行变色呢?很显然是需要对父亲结点进行变色。为什么呢?如果是对插入结点变色,那么和直接插入黑色结点有什么区别呢?所示是要对父亲结点进行变色,即将父亲结点颜色变黑。如果父亲结点颜色变黑,那么该条路径就会多出一个黑色结点,因此需要将爷爷结点颜色变红,如果爷爷结点颜色变红,那么叔叔结点那条路径就会少一个黑色结点。然而,由于爷爷结点颜色是黑色,所以叔叔结点颜色可能是黑色,也可能是红色。所以此时我们就需要对叔叔结点的颜色进行讨论,即如果叔叔结点的颜色是黑色,如果叔叔结点的颜色是红色。如果叔叔结点的颜色是红色时,这种情况我们只需要将叔叔结点的红色变为黑色,这条路径黑色结点颜色就相同。至此,叔叔这条路径和父亲这条路径的黑色结点个数都保持了平衡。然而,由于我们将爷爷结点的颜色变成了红色,那么爷爷的父亲之前如果也是红色,是不是又不平衡了?所以,这里我们需要将爷爷为新插入的结点,重新进行讨论!!!总结来看,如果父亲节点颜色是红,父亲是爷爷的左,插入结点是父亲的左,叔叔结点是红色,我们需要将父亲变黑,爷爷变红,叔叔变黑,然后爷爷为新插入的结点,重新讨论!!!不过,我们想一下,我们在讨论叔叔的颜色时好像并没有发生旋转,仅仅是变色,与父亲是不是爷爷的左,插入结点是不是父亲的左无关啊,所以,在这里我们可以先对叔叔的结点颜色进行讨论,而后再讨论左右;因此,当父亲结点和叔叔结点都是红色时,可这样讨论“如果父亲和叔叔是红色,则父亲变黑,爷爷变红,叔叔变黑,然后爷爷变为新“插入”的结点,重新判断,这种情况我们有个需要注意的就是,如果爷爷是根的话,那么我们直接将爷爷变黑,直接结束即可,如下所示(插入3)(注意:只要不发生旋转,就不需要单独的讨论左还是右!!!):
在这里插入图片描述

1 插入的结点是根:根指向插入的结点,结点变黑,结束
2 插入的结点不是根

2.1 如果插入结点的父亲是黑结点:链接插入结点,结束
2.2 如果插入结点的父亲是红结点

2.2.1如果叔叔的颜色是红:父亲变黑,爷爷变红,叔叔变黑,然后爷爷为新插入的结点,重新讨论

2.2.2如果叔叔的颜色是黑

2.2.2.1如果父亲是爷爷的左

2.2.2.1.1如果插入结点是父亲的左
2.2.2.1.2如果插入结点是父亲的右

2.2.2.2如果父亲是爷爷的右

2.2.2.2.1如果插入结点是父亲的左
2.2.2.2.2如果插入结点是父亲的右

如上所示,这样讨论是不是显得更简单点呢?关于叔叔结点是红色的时候就讨论完了,下面我们看一下叔叔结点是黑色的情况。如果叔叔结点是黑色,那么显然我们就不能将叔叔结点变黑,因为叔叔本来就是黑色。所以,如果此时想要让叔叔这条路径多出一个黑结点,那么我们必须要发生旋转。因此,我们可以有这样一个结论:只有当父亲是红,叔叔是黑时才会发生旋转!!!只有发生旋转时我们才需要具体的讨论左右情况!!!。所以,现在我们就讨论一下左右情况;由于父亲是爷爷的左和父亲是爷爷的右这两种情况基本一样,只是旋转情况相反,因此我们只对父亲是爷爷的左这种情况进行详细讨论,另一种情况就自己研究研究吧,很简单。

对于父亲是红,叔叔是黑时,我们首先看一下如果父亲是爷爷的左,插入结点是父亲的左这种情况,如下图(插入3):
在这里插入图片描述

此时6是3的父亲,NULL是3的叔叔,这里我们可能会有一个疑问,为什么叔叔是NULL?在此种情况,叔叔只可能是NULL,如果叔叔是黑且不是NULL,在3插入之前6一定是叶子结点,然而6的兄弟如果不是NULL,这颗树肯定不会平衡,因此此时6的兄弟一定是NULL。如果此时我们将父亲变黑,父亲这条路径会多出一个黑结点,那么就将爷爷变红,父亲这条路径就少一个黑结点;然而,由于爷爷是父亲和叔叔的公共节点,因此叔叔这条路径同样少了一个黑色结点。如果我们想让叔叔这条路径不少黑色结点,我们应该很自然的就能想到将父亲节点6变成公共黑结点,即右旋,这样这两条路径都不少黑结点,由于黑色结点成为了公共节点,我们此时也不必担心黑结点的父亲是不是红了,因此这样调整后这课红黑树就平衡了,总的调节过程如下:父亲变黑,爷爷变红,以爷爷为支点右旋,如下图所示:
在这里插入图片描述对于父亲是红,叔叔是黑时,我们首先看一下如果父亲是爷爷的左,插入结点是父亲的右这种情况,如下图(插入9):
在这里插入图片描述此种情况,我们观察一下,应该就不难看出。如果我们以父亲为支点进行左旋,这时这个情况就和上种情况一样了,即插入结点是父亲的左,父亲是爷爷的左?所以,对于此种情况,我们只需要进行一下左旋,然后即可将此种情况变换为上一种情况,然后重新判断即可。不过,我们需要注意的是,在进行左旋时,是以父亲为支点左旋,并且要将父亲结点作为新插入的结点重新判断,总结就是(父为新插入的结点,以父亲为支点左旋,重新判断)如下图所示:
在这里插入图片描述以上所有情况都以列出,并进行了详细的讨论,下面综合一下各种情况如下:

1 插入的结点是根:根指向插入的结点,结点变黑,结束
2 插入的结点不是根

2.1 如果插入结点的父亲是黑结点:链接插入结点,结束
2.2 如果插入结点的父亲是红结点

2.2.1如果叔叔的颜色是红:父亲变黑,爷爷变红,叔叔变黑,然后爷爷为新插入的结点,重新讨论

2.2.2如果叔叔的颜色是黑

2.2.2.1如果父亲是爷爷的左

2.2.2.1.1如果插入结点是父亲的左:爷爷变红,父亲变黑,爷爷为支点右旋,结束
2.2.2.1.2如果插入结点是父亲的右:父为新Z,父为支点左旋,重新判断

2.2.2.2如果父亲是爷爷的右

2.2.2.2.1如果插入结点是父亲的左:父为新Z,父为支点右旋,重新判断
2.2.2.2.2如果插入结点是父亲的右:爷爷变红,父亲变黑,爷爷为支点左旋,结束

注意

1 只有当父亲是红,叔叔是黑时才会发生旋转!!!
2 只有发生旋转时我们才需要具体的讨论左右情况!!!
3 如果父亲是红,叔叔是红时,在我们变色后重新判断之前,需要先判断爷爷是不是根,如果爷爷是根,那么将爷爷变黑结束即可。
4 在进行结点插入时,由于一个结点包含三个指针,即左右孩子指针和父指针,所千万不要忘记链接父亲指针。

代码如下

#include <stdio.h>
#include <stdlib.h>
enum COLOR{RED,BLACK};
typedef struct tree
{
	int nValue;
	enum COLOR color; 
	struct tree *pfather;
	struct tree *plchild;
	struct tree *prchild;
}BinaryTree;

void RightRotaryTree(BinaryTree *pTree,BinaryTree **pRoot)
{
	if(pTree == NULL || pTree->plchild == NULL) return;

	BinaryTree *pRotaryChild = pTree->plchild;
	BinaryTree *pRotaryGS = pTree->plchild->prchild;
	BinaryTree *pRotaryFather = pTree->pfather;
	//旋转的点的左孩子重新连接
	pTree->plchild = pRotaryGS;
	if(pRotaryGS != NULL)
	{
		pRotaryGS->pfather = pTree;
	}
	//旋转点的左孩子
	pRotaryChild->prchild = pTree;
	pTree->pfather = pRotaryChild;
	//如果有父亲,连接旋转点的父亲
	pRotaryChild->pfather = pRotaryFather;
	if(pRotaryFather != NULL)
	{
		if(pRotaryFather->plchild == pTree)
		{
			pRotaryFather->plchild = pRotaryChild;
		}
		else
		{
			pRotaryFather->prchild = pRotaryChild;
		}
	}
	else//旋转的是根结点时换根
	{
		*pRoot = pRotaryChild;
	}
}
void LeftRotaryTree(BinaryTree *pTree,BinaryTree **pRoot)
{
	if(pTree == NULL || pTree->prchild == NULL) return;

	BinaryTree *pRotaryChild = pTree->prchild;
	BinaryTree *pRotaryGS = pTree->prchild->plchild;
	BinaryTree *pRotaryFather = pTree->pfather;
	//旋转的点的左孩子重新连接
	pTree->prchild = pRotaryGS;
	if(pRotaryGS != NULL)
	{
		pRotaryGS->pfather = pTree;
	}
	//旋转点的左孩子
	pRotaryChild->plchild = pTree;
	pTree->pfather = pRotaryChild;
	//如果有父亲,连接旋转点的父亲
	pRotaryChild->pfather = pRotaryFather;
	if(pRotaryFather != NULL)
	{
		if(pRotaryFather->plchild == pTree)
		{
			pRotaryFather->plchild = pRotaryChild;
		}
		else
		{
			pRotaryFather->prchild = pRotaryChild;
		}
	}
	else//旋转的是根结点时换根
	{
		*pRoot = pRotaryChild;
	}
}
BinaryTree* SearchNode(BinaryTree *pRoot,int nValue)
{
	if(pRoot == NULL) return NULL;

	BinaryTree *pFather = pRoot;
	BinaryTree *pNode = pRoot;
	while(pFather)
	{
		pNode = pFather;
		if(pFather->nValue < nValue && pFather->prchild)
			pFather = pFather->prchild;
		else if(pFather->nValue > nValue)
			pFather = pFather->plchild;
		else
			return pFather;
	}
	return pNode;
}
//获取叔叔结点
BinaryTree *GetUncle(BinaryTree *pFather)
{
	BinaryTree *pGrandFather = pFather->pfather;
	if(pGrandFather == NULL)
		return NULL;
	else if(pGrandFather->plchild == pFather)
		return pGrandFather->prchild;
	else
		return pGrandFather->plchild;
}
//获取兄弟结点
BinaryTree *GetBrother(BinaryTree *pFather,BinaryTree *pNode)
{
	return pFather->plchild != pNode ? pFather->plchild : pFather->prchild;
}
//插入红黑树的结点
void InsertRBTNode(BinaryTree *pTree,BinaryTree **pRoot,int nValue)//Z为新插入的结点
{
	//为新插入的结点申请空间
	BinaryTree *pTemp = (BinaryTree*)malloc(sizeof(BinaryTree));
	pTemp->color = RED;
	pTemp->nValue = nValue;
	pTemp->plchild = NULL;
	pTemp->prchild = NULL;
	pTemp->pfather = NULL;

	//树为空:直接插入,并且根变黑
	if(*pRoot == NULL)
	{
		*pRoot = pTemp;
		(*pRoot)->color = BLACK;
		return;
	}
	//查找插入结点位置
	BinaryTree *pFather = SearchNode(*pRoot,nValue);
	//如果插入的结点相同
	if(pFather->nValue == nValue)
		return;
	//直接插入
	if(nValue < pFather->nValue)
		pFather->plchild = pTemp;
	else
		pFather->prchild = pTemp;
	//链接父亲
	pTemp->pfather = pFather;

	//父亲结点是黑色:结束
	if(pFather->color == BLACK)
		return;
	//父亲结点是红色
	BinaryTree *pGrandFather = pFather->pfather;
	BinaryTree *pUncle = GetUncle(pFather);
	while(pFather->color == RED)
	{
		//叔叔红:父变黑,叔叔变黑,爷爷变红,爷爷为新Z,爷爷非根重新判断
		if(pUncle && pUncle->color == RED)
		{
			pFather->color = BLACK;
			pUncle->color = BLACK;
			pGrandFather->color = RED;
			pTemp = pGrandFather;
			//如果爷爷是根
			if(pTemp == *pRoot)
			{
				pTemp->color = BLACK;
				return;
			}
			//更新父子关系
			pFather = pTemp->pfather;
			pUncle = GetUncle(pFather);
			pGrandFather = pFather->pfather;

			continue;
		}
		//叔叔黑(叔叔黑才发生旋转,另外叔叔黑可能是空)
		else
		{
			//爷爷为空:父亲变黑,结束
			if(pGrandFather == NULL)
			{
				pFather->color = BLACK;
				return;
			}
			//爷爷非空
			else
			{
				//父亲是爷爷的左
				if(pFather == pGrandFather->plchild)
				{
					//Z是父亲的左:爷爷变红,父亲变黑,爷爷为支点右旋,结束
					if(pTemp == pFather->plchild)
					{
						pGrandFather->color = RED;
						pFather->color = BLACK;
						RightRotaryTree(pGrandFather,pRoot);
						return;
					}
					//Z是父亲的右:父为新Z,父为支点左旋,重新判断
					else
					{
						pTemp = pFather;
						LeftRotaryTree(pTemp,pRoot);
						//更新父子关系
						pFather = pTemp->pfather;
						pGrandFather = pFather->pfather;
						pUncle = GetUncle(pFather);
						continue;
					}
				}
				//父亲是爷爷的右
				else
				{
					//Z是父亲的左:父为新Z,父为支点右旋,重新判断
					if(pTemp == pFather->plchild)
					{
						pTemp = pFather;
						RightRotaryTree(pTemp,pRoot);
						//更新父子关系
						pFather = pTemp->pfather;
						pGrandFather = pFather->pfather;
						pUncle = GetUncle(pFather);
						continue;
					}
					//Z是父亲的右:爷爷变红,父亲变黑,爷爷为支点左旋,结束
					else
					{
						pGrandFather->color = RED;
						pFather->color = BLACK;
						LeftRotaryTree(pGrandFather,pRoot);
						return;
					}
				}
			}
		}
	}
}

//删除结点
void DeleteRBTNode(BinaryTree *pTree,BinaryTree **pRoot,int nValue)
{
	if(*pRoot == NULL) return;
	//查找要删除的结点,并转换(真正要删除的只有一个孩子或无孩子)
	BinaryTree *pNode = SearchNode(pTree,nValue);
	BinaryTree *pMark = pNode;//标记要删除的结点
	//如果没找到,则直接返回
	if(pNode == NULL || pNode->nValue != nValue)
	{
		printf("There don't have the nValue int the tree.\n");
		return;
	}
	//如果找到了则将结点转换:转换成真正要删除的结点
	BinaryTree *pFather = pNode->pfather;
	//寻找左边最右替换删除结点
	if(pNode->plchild && pNode->prchild)//有两个孩子才进行转换
	{
		pNode = pNode->plchild;
		while(pNode->prchild)
			pNode = pNode->prchild;
		pMark->nValue = pNode->nValue;
	}
	//如果删除的是根
	if((*pRoot)->nValue == nValue)
	{
		//如果根无孩子:直接删除,结束
		if((*pRoot)->plchild == NULL && (*pRoot)->prchild == NULL)
		{
			free(*pRoot);
			*pRoot = NULL;
			return;
		}
		//如果根有一个孩子:直接删除,红孩子成为新根,根变黑,结束
		if(((*pRoot)->plchild == NULL && (*pRoot)->prchild != NULL) || ((*pRoot)->plchild != NULL && (*pRoot)->prchild == NULL))
		{
			BinaryTree *pDel = *pRoot;
			*pRoot = (*pRoot)->plchild == NULL? (*pRoot)->prchild:(*pRoot)->plchild;
			(*pRoot)->color = BLACK;
			(*pRoot)->pfather = NULL;
			free(pDel);
			pDel = NULL;
			return;
		}
	}
	//-----------下面删除的是非根的情况-------------------(因为上面判断的就是删除的是根的情况,因此走下来就一定是非根)
	//如果删除的是红结点:直接删除,父亲指向空,结束
	pFather = pNode->pfather;
	//printf("pFather[%d]\n",pFather->nValue);
	if(pNode->color == RED)
	{
		if(pFather->plchild == pNode)
			pFather->plchild = NULL;
		else 
			pFather->prchild = NULL;

		printf("pNode[%d]\n",pNode->nValue);
		free(pNode);
		pNode = NULL;
		return;
	}
	//如果删除的非根且是黑结点
	else
	{
		//有一个孩子:直接删除,孩子颜色变黑,爷爷指向孙子,结束
		if(pNode->plchild != NULL)
		{
			if(pFather->plchild == pNode)
				pFather->plchild = pNode->plchild;
			else
				pFather->prchild = pNode->plchild;

			pNode->plchild->pfather = pFather;
			pNode->plchild->color = BLACK;

			free(pNode);
			pNode = NULL;
			return;
		}
		else if(pNode->prchild != NULL)
		{
			if(pFather->plchild == pNode)
				pFather->plchild = pNode->prchild;
			else
				pFather->prchild = pNode->plchild;

			pNode->prchild->pfather = pFather;
			pNode->prchild->color = BLACK;

			free(pNode);
			pNode = NULL;
			return;
		}
		//无孩子
		else
		{
			//首先将结点删除
			if(pFather->plchild == pNode)
				pFather->plchild = NULL;
			else
				pFather->prchild = NULL;

			free(pNode);
			pNode = NULL;
			//获取兄弟结点
			BinaryTree *pBrother = GetBrother(pFather,pNode);
			while(1)
			{
				//如果兄弟是红结点
				if(pBrother->color == RED)
				{
					//如果兄弟是父亲的右:父变红,兄弟变黑,以父亲为支点左旋,更新结点信息,重新判断
					if(pBrother == pFather->prchild)
					{
						pFather->color = RED;
						pBrother->color = BLACK;
						LeftRotaryTree(pFather,pRoot);
						pBrother = GetBrother(pFather,pNode);
						continue;
					}
					//如果兄弟是父亲的左:父变红,兄弟变黑,以父亲为支点右旋,更新结点信息,重新判断
					else
					{
							printf("11 左红右空[%d]\n",pBrother->nValue);
						pFather->color = RED;
						pBrother->color = BLACK;
						RightRotaryTree(pFather,pRoot);
						pBrother = GetBrother(pFather,pNode);
						continue;
					}
				}
				//如果兄弟是黑结点
				else
				{
					//如果兄弟是父亲的右
					if(pBrother == pFather->prchild)
					{
						//如果左侄子红右侄子空:兄弟变红,左侄子变黑,以兄弟为支点右旋,更新结点信息,重新判断
						if(pBrother->plchild && pBrother->plchild->color == RED && pBrother->prchild == NULL)
						{
							pBrother->color = RED;
							pBrother->plchild->color = BLACK;
							RightRotaryTree(pBrother,pRoot);

							//更新结点关系
							pBrother = GetBrother(pFather,pNode);
							continue;
						}
						//如果右侄子红:兄弟变父色,父亲变黑,右侄子变黑,以父亲为支点左旋,结束
						else if(pBrother->prchild && pBrother->prchild->color == RED)
						{
							pBrother->color = pFather->color;
							pFather->color = BLACK;
							pBrother->prchild->color = BLACK;
							LeftRotaryTree(pFather,pRoot);

							return;
						}
						//如果俩侄子全黑
						else
						{
							//如果父亲红:兄弟变红,父为变黑,结束
							if(pFather->color == RED)
							{
								pBrother->color = RED;
								pFather->color = BLACK;

								return;
							}
							//如果父亲黑:兄弟变红,父为新Z,重新判断(Z指代要“删除”的结点)
							else
							{
								pBrother->color = RED;
								pNode = pFather;
								//如果此时pNode 为根,则将根变黑,结束
								if(pNode == *pRoot)
								{
									pNode->color = BLACK;
									return;
								}
								pFather = pNode->pfather;
								pBrother = GetBrother(pFather,pNode);

								continue;
							}
						}
					}			
					//如果兄弟是父亲的左
					else
					{
						//如果左侄子红:兄弟变为父亲的颜色,父亲变黑,左侄子变黑,以父亲为支点右旋,结束
						if(pBrother->plchild && pBrother->plchild->color == RED)
						{
							pBrother->color = pFather->color;
							pBrother->plchild->color = BLACK;
							pBrother->plchild->color = BLACK;
							RightRotaryTree(pFather,pRoot);

							return;
						}
						//如果右侄子红左侄子空:兄弟变红,右侄子变黑,以兄弟为支点左旋,更新结点信息,重新判断
						else if(pBrother->plchild == NULL && pBrother->prchild && pBrother->prchild->color == RED)
						{
							pBrother->color = RED;
							pBrother->prchild->color = BLACK;
							LeftRotaryTree(pBrother,pRoot);
							//更新结点信息
							pBrother = GetBrother(pFather,pNode);
							continue;
						}
						//如果俩侄子全黑
						else
						{
							//如果父亲红:兄弟变红,父为变黑,结束
							if(pFather->color == RED)
							{
							printf("7 左红右空[%d]\n",pBrother->nValue);
								pBrother->color = RED;
								pFather->color = BLACK;

								return;
							}
							//如果父亲黑:兄弟变红,父为新Z,重新判断(Z指代要“删除”的结点)
							else
							{
								pBrother->color = RED;
								pNode = pFather;
								//如果此时pNode 为根,则将根变黑,结束
								if(pNode == *pRoot)
								{
									pNode->color = BLACK;
									return;
								}
								pFather = pNode->pfather;
								pBrother = GetBrother(pFather,pNode);

								continue;
							}
						}
					}
				}
			}
		}
	}
}
//创建RBT
void CreateRBT(BinaryTree **pTree)
{
	//添加结点
	printf("please input node value (0 is quit)\n");
	int nValue;
	//while(scanf("%d",&nValue) && nValue)
	int arr[] = {20,11,9,3,1,6,10,16,14,18,19,36,28,23,33,30,49,58};
	int nLen = sizeof(arr)/sizeof(arr[0]);
	for(int i = 0;i < nLen;i++)
	{
		InsertRBTNode(*pTree,pTree,arr[i]);
		//printf("please input node value (0 is quit)\n");
	}
}
//中序遍历
void MidOrderTree(BinaryTree *pTree)
{
	if(pTree == NULL) return;

	MidOrderTree(pTree->plchild);
	printf("nValue[%d]\t color[%d]\n",pTree->nValue,pTree->color);
	MidOrderTree(pTree->prchild);

}
//前序遍历
void FrontOrderTree(BinaryTree *pTree)
{
	if(pTree == NULL) return;

	printf("nValue[%d]\t color[%d]\n",pTree->nValue,pTree->color);
	FrontOrderTree(pTree->plchild);
	FrontOrderTree(pTree->prchild);

}
int main()
{
	BinaryTree *pTree = NULL;

	CreateRBT(&pTree);
	printf("Create the tree is\n");
	MidOrderTree(pTree);

	int select = 0;;
	int nValue = 0;
	while(select != -1)
	{
		printf("\nPlease select DeleteNode or InsertNode:0 InsertNode  1 DeleteNode  -1 Quit\n");
		scanf("%d",&select);
		if(select == 0)
		{
			printf("\nPlease input InsertNode nValue\n");
			scanf("%d",&nValue);
			InsertRBTNode(pTree,&pTree,nValue);
			printf("\nAfter InsertNode ther Node[%d],ther MideReverse\n",nValue);
			MidOrderTree(pTree);
			continue;
		}
		else if(select == 1)
		{
			printf("\nPlease input the node of you wand to delete\n");
			scanf("%d",&nValue);
			DeleteRBTNode(pTree,&pTree,nValue);
			printf("\nAfter Delete the Node [%d],ther MidReverse:\n",nValue);
			MidOrderTree(pTree);
			continue;
		}

	}

	return 0;
}

标签:黑树,困扰,pNode,color,结点,插入,父亲,进来,pFather
来源: https://blog.csdn.net/qq_43450920/article/details/120154952

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有