![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ac63d5453c3da24c23918468cf4abc48.png)
代码:
/*
* 作者:流放的未来
* 时间:2020/10/29/8/43
* 红黑树定义:
* 1. 根必须为黑。
* 2. 树上节点非红即黑。
* 3. 两个节点不能同时为红色。
* 4. 路径上的黑节点个数一致。
* 5. 所有空节点,默认为黑,俗称黑哨兵。
*/
//用到C语言的输入输出等基础函数因此需要 stdio
//需要malloc申请地址空间 stdlib
#include<stdio.h>
#include<stdlib.h>
//定义红黑树的结构体,保存红黑树节点的信息
typedef struct treeNode
{
int nValue;
int nColor;
struct treeNode *pLeft;
struct treeNode *pRight;
struct treeNode *pFather;
}RBT;
RBT *pRBT = NULL;
//设置枚举更容易操作,让代码更加清晰,实际上RED=0,BLACK=1。
enum COLOR{RED,BLACK};
//分析所需函数
//首先添加:需要什么,按照我们分析的步骤
/*
* 一、有根吗?:
1. 没有好办,直接把现在的点变成根,根指针赋值当前节点,
* 当前节点如何的得到,因此得出需要一个RBT *GetRBTNode(int nValue)的节点
* (初始化节点颜色为红,数值可以给定或者数组,这里选择数组,因为我们主要为了构建RBT)。
* 2. 有根。
* 二、父亲颜色是啥?因此发现我们需要得到父亲的节点,我们结构体定义了找到父亲的指针,因此不需要函数。
* 1. 黑色:直接添加。
* 2. 红色:
* 三、叔叔啥颜色:因此需要有个得到叔叔的函数RBT *GetUncle(RBT *pNode);
* 1. 红色:父亲和叔叔同时变黑,爷爷变红,标记转移到爷爷,继续讨论,;
* (当前无法解决,向上寻求帮助)(因此可以看出需要将三的判断做成循环)
* 2. 黑色:判断父亲位置?:直接可以得到不需要做成函数。
* 四、1. 父亲在左:标记位置?需要旋转,因此需要做出旋转函数
* 五、判断孩子也就是标记位置
* 1. 父亲的左:父亲变黑,爷爷变红,以爷爷为支点右旋,注意父亲可能会变成根。
* 2. 父亲的右:以父亲为支点左旋,标记给父亲(变化树结构转化成我们可以解决的)
* 四、2. 父亲在右:标记位置?
* 五、判断孩子也就是标记位置
* 1. 父亲的左:右旋,标记给父亲(变成我们可以修改的结构)
* 2. 父亲的右:父亲变黑,爷爷变红,左旋,注意父亲可能会成为根
*/
//通过分析得出以下所需函数
RBT *GetRBTNode(int nValue);
void CreateRBT(int arr[], int nLength);
void AddRBTNode(int nValue);
RBT *GetUncle(RBT *pNode);
void InorderTraversal();
void BalanceREDBALCK(RBT *pNode);
void RightRotation(RBT **ppTree);
void LeftRotation(RBT **ppTree);
void CreateRBT(int arr[], int nLength)
{
//边界判断
/*
* 建议编程方式:
* 1. 边界判断。准备功能测试用例,可以先定义个变量,设计到一个设计一个用例,用于测试。
* 2. 变量申请。想好当前可能需要的变量放到边界判断前,集体定义,便于观看。
* 3. 初始化。永远记得边界判断完立马初始化,别管有没有用,养成习惯。
*/
//------------------------定义阶段:---------------------------------------------------
int i;
//----------------------------边界判断阶段:--------------------------------------------
if(NULL==arr || nLength<=0)return;
//------------------------------------------初始化阶段:--------------------------------
i = 0;
//------------------具体流程阶段:------------------------------------------------------
for(i=0; i<nLength; i++)
{
AddRBTNode(arr[i]);
}
}
void AddRBTNode(int nValue)
{
RBT *pNode = GetRBTNode(nValue);
RBT *pTemp = NULL;
if(pRBT == NULL)
{
BalanceREDBALCK(pNode);
return;
}
pTemp = pRBT;
while(pTemp)
{
if(nValue > pTemp->nValue)
{
if(pTemp->pRight == NULL)
{
pTemp->pRight = pNode;
pNode->pFather = pTemp;
BalanceREDBALCK(pNode);
return;
}
pTemp = pTemp->pRight;
}
else if(nValue < pTemp->nValue)
{
if(pTemp->pLeft == NULL)
{
pTemp->pLeft = pNode;
pNode->pFather = pTemp;
BalanceREDBALCK(pNode);
return;
}
pTemp = pTemp->pLeft;
}
else
{
printf("构造错误,不允许出现重复");
exit(1);
}
}
}
//注意,只要标记转移就是重新开始判断的情况,只要旋转就需要考虑根,
//具体需不需要在分析,但是一定要记得旋转看根,根是最容易被忽略的地方。
void BalanceREDBALCK(RBT *pNode)
{
//-------------------------申请父亲,叔叔,爷爷节点。-------------------------
RBT *pFather;
RBT *pUncle;
RBT *pGrandFather;
//--------------------------------节点不存在不用调整-------------------------
if(pNode == NULL)return;
//-------------------------一、判断根是否存在
//-----------------------------1. 根不存在的情况-----------------------------
if(NULL == pNode->pFather)
{
pNode->nColor = BLACK;
pRBT = pNode;
return;
}
else
{
//-------------------------2. 根存在-------------------------------------
//----------------------二、判断父亲颜色-------------------------
while(pNode != NULL)
{
//-------------------------初始化父亲和叔叔-------------------------
pFather = pNode->pFather;
pUncle = GetUncle(pNode);
//-------------------------不是根肯定有父亲,因从不需要判断父亲是否存在-------------------------
//----------------------1. 父亲黑色,不需要调整-------------------------
if(BLACK==pFather->nColor)
{
return;
}
//----------------------2. 父亲红色,孩子红色,需要调整-------------------------
else
{
//-------------------------父亲红色,爷爷肯定存在而且是黑色-------------------------
pGrandFather = pFather->pFather;
//----------------三、判断叔叔颜色-------------------------
//-------------------------叔叔不一定会存在,记得判空-------------------------
//--------------------1. 叔叔红色-------------------------
if(pUncle!=NULL && RED==pUncle->nColor)
{
//----------------叔叔变黑,父亲变黑,爷爷变红,标记给爷爷,注意爷爷是根的情况
pUncle->nColor = BLACK;
pFather->nColor = BLACK;
pGrandFather->nColor = RED;
pNode = pGrandFather;
//-------------------------爷爷是根吗-------------------------
if(pNode->pFather == NULL)
{
pNode->nColor = BLACK;
pRBT = pNode;
return;
}
//-------------------------重新讨论-------------------------
continue;
}
else
{
//----------------2. 叔叔黑色-------------------------
//--------------四、父亲位置
//----------------1. 左侧
if(pGrandFather->pLeft == pFather)
{
//----------五、孩子位置,也就是标记位置-------------------------
//--------------1.左侧,父亲变黑,爷爷变红,右旋,注意根的情况-------------------------
if(pFather->pLeft == pNode)
{
pFather->nColor = BLACK;
pGrandFather->nColor = RED;
RightRotation(&pGrandFather);
return;
}
//-------------2. 右侧,左的右,左旋,变成左的左
else
{
LeftRotation(&pFather);
pNode = pFather->pLeft;
}
}
//-------------2. 右侧,-------------------------
else
{
//------五、标记的位置-------------------------
//----------1.父亲的右侧,右的右,父亲变黑,爷爷变红,左旋,注意根
if(pFather->pRight == pNode)
{
pFather->nColor = BLACK;
pGrandFather->nColor = RED;
LeftRotation(&pGrandFather);
return;
}
//----------2. 左侧,右的左,右旋,变成右的右
else
{
RightRotation(&pFather);
pNode = pFather->pRight;
}
}
}
}
}
}
}
RBT *GetUncle(RBT *pNode)
{
if(pNode==NULL || pNode->pFather==NULL || pNode->pFather->pFather==NULL)return NULL;
if(pNode->pFather == pNode->pFather->pFather->pLeft)
return pNode->pFather->pFather->pRight;
return pNode->pFather->pFather->pLeft;
}
RBT *GetRBTNode(int nValue)
{
RBT *pNode = (RBT *)malloc(sizeof(RBT));//malloc 申请地址,返回的是void *泛型指针
//可以调用memset(pNode, 0, sizeof(RBT)),除了nValue其他的都不需要了
pNode->nValue = nValue;
pNode->nColor = RED;
pNode->pFather = NULL;
pNode->pLeft = NULL;
pNode->pRight = NULL;
return pNode;
}
void RightRotation(RBT **ppTree)
{
RBT *pLeft = NULL;
RBT *pFather = NULL;
if(*ppTree==NULL || (*ppTree)->pLeft==NULL)return;
pFather = *ppTree;
pLeft = (*ppTree)->pLeft;
pFather->pLeft = pLeft->pRight;
pLeft->pRight = pFather;
if(pFather->pFather == NULL)
{
pRBT = pLeft;
pLeft->nColor = BLACK;
}
else if(pFather->pFather->pLeft == pFather)
pFather->pFather->pLeft = pLeft;
else
pFather->pFather->pRight = pLeft;
if(pFather->pLeft != NULL)
{
pFather->pLeft->pFather = pFather;
}
pLeft->pFather = pFather->pFather;
pFather->pFather = pLeft;
*ppTree = pLeft;
}
void LeftRotation(RBT **ppFather)
{
RBT *pRight = NULL;
RBT *pFather = *ppFather;
if(pFather==NULL || pFather->pRight==NULL)return;
pRight = pFather->pRight;
pFather->pRight = pRight->pLeft;
pRight->pLeft = pFather;
if(pFather->pFather == NULL)
{
pRBT = pRight;
pRBT->nColor = BLACK;
}
else
{
if(pFather->pFather->pLeft == pFather)
pFather->pFather->pLeft = pRight;
else
pFather->pFather->pRight = pRight;
}
if(pFather->pRight != NULL)
pFather->pRight->pFather = pFather;
pRight->pFather = pFather->pFather;
pFather->pFather = pRight;
*ppFather = pRight;
}
void InorderTraversal(RBT *pRBT)
{
if(pRBT== NULL)return;
InorderTraversal(pRBT->pLeft);
printf("数值%d\n",pRBT->nValue);
printf("颜色%d\n",pRBT->nColor);
InorderTraversal(pRBT->pRight);
}
int main()
{
int arr[] = {11,2,7,4,5,12,14};
CreateRBT(arr,sizeof(arr)/sizeof(arr[0]));
InorderTraversal(pRBT);
return 0;
}