红黑树
一、性质:
1.红黑树的节点颜色不是红就是黑
2.红黑树的根节点一定是黑色的
3.终端节点(叶子节点为空的左右子树)是黑的
4.没有两个红节点为父子关系
5.从任意节点出发到达各各终端节点,各条路径上黑节点的数目必须是完全相同的
二、添加操作流程:
一、先按左大右小的规律找到对应的添加位置
二、进行颜色调整
1.树为空
节点为黑 以此为根 return
2.父为黑
return
3.父为红
3.1叔为红
父变黑 叔变黑 爷变红 爷为新节点向上调整
同时,如爷为根 return
3.2叔为黑
3.2.1父为爷左
3.2.1.1z为父右
以父为新节点 并以此为支点 左旋
3.2.1.2z为父左
父为黑 爷为红
以爷为支点右旋 return
3.2.2父为爷右
3.2.2.1z为父左
以父为新节点 右旋
3.2.2.2z为父右
父为黑 爷为红
以爷为支点左旋 return
代码:
//这里涉及到 树的旋转 问题,大家可以参考我之前写的博客
https://blog.youkuaiyun.com/Water_st/article/details/99223178
void RBTADD(int num)
{
//创建新节点
BinaryTree* pNode = new BinaryTree;
pNode->colour = RED;
pNode->n_value = num;
pNode->pFather = NULL;
pNode->pLeft = NULL;
pNode->pRight= NULL;
BinaryTree* pRoot = pRBT;
//1.树空
if(pRoot == NULL)
{
pNode->colour = BLACK;
pRBT = pNode;
return ;
}
//找到合适的插入位置
while(1)
{
if(pNode->n_value > pRoot->n_value)
{
if(pRoot->pRight == NULL)
{
pRoot->pRight = pNode;
pNode->pFather = pRoot;
break;
}
pRoot = pRoot->pRight;
}
else if(pNode->n_value < pRoot->n_value)
{
if(pRoot->pLeft == NULL)
{
pRoot->pLeft = pNode;
pNode->pFather = pRoot;
break;
}
pRoot = pRoot->pLeft;
}
else
throw("插入位置不存在");
}
//找到插入位置后进行 结点的调整
BinaryTree* pUncle = NULL;
BinaryTree* pGrand = NULL;
BinaryTree* pFather = NULL;
while(1)
{
//2.父 黑
if(pNode->pFather->colour == BLACK)
return ;
pFather = pNode->pFather;
pUncle = GetUncle(pFather);
pGrand = pFather->pFather;
//3.父红
//3.1叔红
if(pUncle->colour == RED)
{
pUncle->colour = BLACK;
pFather->colour = BLACK;
pGrand->colour = RED;
pNode = pGrand;
if(pGrand->pFather == NULL)//根节点
{
pGrand->colour = BLACK;
break;
}
continue;
}
//3.2叔黑
if(pUncle->colour == BLACK || pUncle == NULL)
{//3.2.1父是爷左
if(pFather == pGrand->pLeft)
{
//3.2.1.1z是父的右
if(pNode == pFather->pRight)
{
pNode = pFather;
LeftRoate(&pNode);
continue;
}//3.2.1.2z是父的左
if(pNode == pFather->pLeft)
{
pFather->colour = BLACK;
pGrand->colour = RED;
RightRoate(&pGrand);
break;
}
}
//3.2.2父是爷的右
if(pFather == pGrand->pRight)
{
//3.2.2.1z是父的左
if(pNode == pFather->pLeft)
{
pNode = pFather;
RightRoate(&pNode);
continue;
}//3.2.2.2z是父的右
if(pNode == pFather->pRight)
{
pFather->colour = BLACK;
pGrand->colour = RED;
LeftRoate(&pGrand);
break;
}
}
}
}
}
三、删除操作流程:
//2019/8/16 不好意思,拖更了
一、找到被删除位置:
二、根据BST性质 找左的最右 或 右的最左 来替换被删除的值
三、根据颜色进行调整
1.根 没有孩子 直接删除
2.根 有一个孩子 孩子变黑为新根 删原根
3.节点为红 直接删除
4.黑 非根 有一个红孩子 将此孩子子变黑 与爷爷相连 删除父亲
(假删除)//将被替换节点进行删除
5.黑 非根 没有孩子
5.1兄弟为红
父变红 兄变黑
5.1.1兄为右
以父为支点左旋
兄 = 兄->左
continue;
5.1.2兄为左
以父为支点右旋
兄 = 兄->右
continue;
5.2兄为黑
5.2.1两个侄子为黑
5.2.1.1父为红
兄变红 父为黑 return
5.2.1.2父为黑
兄变红 以父为新节点 更新 父
判断父是否为空(根)return
更新 兄
continue;
5.2.2左侄红右侄黑
5.2.2.1兄为右
兄为红 左侄子为黑 以兄为支点右旋
更新兄弟
continue;
5.2.2.2兄为左
父色给兄 父为黑 左侄子为黑
以父为支点右旋
return
5.2.3右侄子为红
5.2.3.1兄为左
兄为红 右侄子为黑
以兄支点左旋
更新兄弟
continue
5.2.3.2兄为右
父色给兄 父为黑 右侄子为黑
以父为支点左旋
reutrn
void RBTDEL(int num)
{
BinaryTree* pTemp = pRBT;
//一`先找到这个节点
while(pTemp)
{
if(pTemp->n_value == num)
{
break;
}
else if(pTemp->n_value > num)
{
pTemp = pTemp->pLeft;
}else if(pTemp->n_value < num)
{
pTemp = pTemp->pRight;
}
}
if(pTemp == NULL)
return ;
//二`找到他的替代节点
BinaryTree* pMark = NULL;
if(pTemp->pLeft != NULL && pTemp->pRight != NULL)//有2个孩子
{
pMark = pTemp;
pTemp = pTemp->pLeft;
while(pTemp->pRight != NULL )
{
pTemp = pTemp->pRight;
}
pMark->n_value = pTemp->n_value;
}
//三`颜色分析
if(pTemp == pRBT)
{////1。根节点没孩子
if(!pTemp->pLeft && !pTemp->pRight)
{
delete pTemp;
pTemp = NULL;
pRBT = NULL;
}//2.根节点 有一个孩子
else if(pTemp->pLeft != NULL || pTemp->pRight != NULL)
{
pRBT = pTemp->pLeft?pTemp->pLeft:pTemp->pRight;
pRBT->colour = BLACK;
delete pTemp;
pTemp = NULL;
}
return ;
}
//3.被删除节点为红色
if(pTemp->colour == RED)
{
delete pTemp;
pTemp = NULL;
return ;
}
BinaryTree* pNode = pTemp->pFather;
BinaryTree* pBrother = GetUncle(pTemp);
while(1)
{
//4.黑 非根 有一个红孩子
if(pTemp->pFather != NULL && pTemp->colour == BLACK)
{
if(pTemp->pLeft !=NULL || pTemp->pRight != NULL)
{
BinaryTree* pDl = pTemp;
pTemp = pTemp->pLeft?pTemp->pLeft:pTemp->pRight;
pTemp->colour = BLACK;
if(pDl == pTemp->pLeft)
{
pNode->pLeft = pTemp;
}else
{
pNode->pRight = pTemp;
}
delete pDl;
pDl = NULL;
return ;
}
}
//假删除
if(pTemp == pNode->pLeft)
pNode->pLeft = NULL;
else if(pTemp == pNode->pRight)
pNode->pRight = NULL;
//5.如果黑 没有孩子
if(pTemp->pLeft == NULL && pTemp->pRight == NULL)
{
//5.1兄 为红
if(pBrother->colour == RED)
{
//兄为黑 父为红
pBrother->colour = BLACK;
pNode->colour = RED;
//5.1.1节点为 父左
if(pNode->pLeft == pTemp )
{
LeftRoate(&pNode);
pBrother = pBrother->pLeft;
continue;
}//5.1.2 节点为父右
if(pTemp = pTemp->pRight)
{
RightRoate(&pNode);
pBrother = pBrother->pRight;
continue;
}
}
//5.2兄为黑
if(pBrother->colour == BLACK)
{
//5.2.1 左右侄子为黑
if(pBrother->pLeft == NULL&&pBrother->pRight==NULL||
(pBrother->pLeft!= NULL && pBrother->pLeft->colour == BLACK )&&
(pBrother->pRight!= NULL &&pBrother->pRight->colour == BLACK)
)
{//5.2.1.1如果父亲为红
if(pNode->colour == RED)
{
pBrother->colour = RED;
pNode->colour = BLACK;
return ;
}//5.2.1.2如果父亲为黑
if(pNode->colour == BLACK)
{//兄红 父为新节点向上调整 更新父 兄
pBrother->colour = RED;
pTemp = pNode;
pNode = pTemp->pFather;
if(pNode == NULL)
return ;
pBrother = GetUncle(pTemp);
}
}
//5.2左侄子为红 右侄子黑
if((pBrother->pLeft!=NULL && pBrother->pLeft->colour == RED) &&
(!pBrother->pRight||pBrother->pRight->colour == BLACK))
{
//5.2.1兄为右
if(pNode->pRight == pBrother)
{
pBrother->colour = RED;
pBrother->pLeft->colour = BLACK;
RightRoate(&pBrother);
pBrother = pNode->pRight;
continue;
}
//5.2.2兄为左
if(pNode->pLeft == pBrother)
{
pBrother->colour = pNode->colour;
pNode->colour = BLACK;
pBrother->pLeft->colour = BLACK;
RightRoate(&pNode);
return ;
}
}
if(pBrother->pRight != NULL || pBrother->pRight->colour == BLACK)
{
//5.2.3右侄子红
//5.2.3.1兄为左
if(pBrother == pNode->pLeft)
{
pBrother->colour = RED;
pBrother->pRight->colour = BLACK;
LeftRoate(&pBrother);
pBrother = pNode->pLeft;
continue;
}
else//5.2.3.1兄为右
{
pBrother->colour = pNode->colour;
pNode->colour = BLACK;
pNode->pRight->colour = BLACK;
LeftRoate(&pNode);
return ;
}
}
}
}
}
}