红黑树的特性:
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;
}