gitee仓库:https://gitee.com/WangZihao64/data-structure-and-algorithm/tree/master/RBTree
目录
- 概念
- 红黑树的性质
- 红黑树的调整规则
概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的
红黑树的性质
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
红黑树的调整规则
插入的顺序和avl树一样,根结点为黑色,插入新结点为红色,因为从该结点到后代结点都有相同数量的黑色结点,如果插入黑色,有很大的可能性会失败,所以插入红色结点是最为保险的做法,然后在依据规则进行调整,一般有3种情况
- 情况一:cur为红,parent为红,grandfather为红,uncle存在且为红色
- 解决方法:parent,uncle变黑,然后把grandfather给cur,继续向上调整
-
情况二:cur为红,parent为红,grandfather为黑,uncle不存在||uncle存在且为黑色
-
解决方法:parent为grandfather的左孩子,cur为parent的左孩子,对grandfather右旋
parent为grandfather的右孩子,cur为parent的右孩子,对grandfather左旋 **parent变黑,grandfather变红**
- 情况三:cur为红,parent为红,grandfather为黑,uncle不存在||uncle存在且为黑色
- 解决方法:parent为grandfather的左孩子,cur为parent的右孩子,对parent左旋,对grandfather右旋
parent为grandfather的右孩子,cur为parent的左孩子,对parent右旋,对grandfather左旋
cur变黑,grandfather变红
bool Insert(const pair<K,V>& kv)
{
if(_root== nullptr)
{
//根节点为黑色
_root=new Node(kv);
_root->_col=BLACK;
return true;
}
Node* cur=_root;
Node* parent=nullptr;
while(cur)
{
if(cur->_kv.first>kv.first)
{
parent=cur;
cur=cur->_left;
}
else if(cur->_kv.first<kv.first)
{
parent=cur;
cur=cur->_right;
}
//遇到相同的值,返回false
else
{
return false;
}
}
cur=new Node(kv);
if(kv.first>parent->_kv.first)
{
parent->_right=cur;
cur->_parent=parent;
}
else
{
parent->_left=cur;
cur->_parent=parent;
}
//parent不为空&&parent为红色需要进行调整
while(parent&&parent->_col==RED)
{
Node* grandfather=parent->_parent;
if(grandfather->_left==parent)
{
//情况一:cur为红,parent为红,uncle存在&&为红
//把p,u变为black,g变为red
Node* uncle=grandfather->_right;
if(uncle&&uncle->_col==RED)
{
parent->_col=BLACK;
uncle->_col=BLACK;
grandfather->_col=RED;
//把g变为cur继续向上调整
cur=grandfather;
parent=cur->_parent;
}
//uncle不存在||uncle存在&&为黑色
//这两个可以直接break,因为无论是不是子树,root都是黑色
else
{
//情况二:parent->left=cur
//对grandfater右旋
//p变black,g变red
if(parent->_left==cur)
{
RotateR(grandfather);
parent->_col=BLACK;
grandfather->_col=RED;
}
//情况三:parent->right=cur
//先对cur左旋,在对grandfather右旋
//这是会变为情况二,cur变black,g变red
else
{
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
//grandfather->right=cur
//和grandfather->left=cur类似
else
{
//情况一:cur为红,parent为红,uncle存在&&为红
//把p,u变为black,g变为red
Node* uncle=grandfather->_left;
if(uncle&&uncle->_col==RED)
{
parent->_col=BLACK;
uncle->_col=BLACK;
grandfather->_col=RED;
//把g变为cur继续向上调整
cur=grandfather;
parent=cur->_parent;
}
//uncle不存在||uncle存在&&为黑色
//这两个可以直接break,因为无论是不是子树,root都是黑色
else
{
//情况二:parent->right=cur
//对grandfater左旋
//p变black,g变red
// g
// p
// c
if(parent->_right==cur)
{
RotateL(grandfather);
parent->_col=BLACK;
grandfather->_col=RED;
}
//情况三:parent->left=cur
//先对cur右旋,在对grandfather左旋
//这是会变为情况二,cur变black,g变red
// g
// p
// c
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
//根节点永远是黑色
_root->_col=BLACK;
return true;
}
void RotateL(Node* parent)
{
Node* subR=parent->_right;
//右子树的左子树
Node* subRL=subR->_left;
//旋转的这棵树有可能是子树,所以需要保存parent的parent
Node* pparent=parent->_parent;
parent->_right=subRL;
subR->_left=parent;
//subLR可能不存在,需要单独判断
if(subRL!= nullptr)
{
subRL->_parent = parent;
}
parent->_parent=subR;
subR->_parent=pparent;
//如果parent不是子树,就需要把_root给subR
if(pparent== nullptr)
{
_root=subR;
}
//如果parent是子树的话,需要改变pparent的指向
else if(pparent!= nullptr)
{
//子树是pparent的左子树/右子树,需要把pparent-left/->right指向subR
if(pparent->_left==parent)
{
pparent->_left=subR;
}
else if(pparent->_right==parent)
{
pparent->_right=subR;
}
}
}
//右旋和左旋是一样的
void RotateR(Node* parent)
{
Node* subL=parent->_left;
Node* subLR=subL->_right;
Node* pparent=parent->_parent;
parent->_left=subLR;
subL->_right=parent;
if(subLR!= nullptr)
{
subLR->_parent=parent;
}
parent->_parent=subL;
subL->_parent=pparent;
if(pparent== nullptr)
{
_root=subL;
}
else if(pparent!= nullptr)
{
if(pparent->_left==parent)
{
pparent->_left=subL;
}
else if(pparent->_right==parent)
{
pparent->_right=subL;
}
}
}