1.红黑树的定义与性质
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过 对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩 倍,因而是接近平衡的。
性质:
- 每个结点不是红色就是黑色。
- 根节点是黑色的。
- 如果一个节点是红色的,则它的两个孩子结点是黑色的。
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点。
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点。
2.节点定义
struct RBTNode
{
RBTNode(const pair<K,V>& data = pair<K,V>())
:_parent(nullptr)
,_right(nullptr)
,_left(nullptr)
,color(red)
,_data(data)
{}
pair<K,V> _data;
RBTNode<K,V>* _parent;
RBTNode<K,V>* _right;
RBTNode<K,V>* _left;
COLOR color;
};
3.如何调整?
3.1 情况一:父节点为红,叔叔节点为红
来看下面这种情况:
插入cur节点时,左侧出现两个连续的红色节点,此时就需要调整,我们发现叔叔节点u存在,所以处理方式是,将父节点与叔叔节点同时变黑,并将祖父节点g变为红色。然后cur交换至g,继续向上调整。
3.2 情况2:父节点为红,叔叔节点为黑/不存在
此时分为两种情况:
情况a: 父节点为祖父节点的左(右)节点,插入节点cur为父节点的左(右)节点。
来看这种情况:
插入节点为父节点的左孩子,处理方法为:对p进行右旋转,随后将g变为红,p变为黑。
**情况b:**父节点为祖父节点的左(右)节点,插入节点cur为父节点的右(左)节点。
来看这种情况:
插入节点为父亲的左孩子,处理方法为:
先对父节点p进行做单旋,得到如下结果,此时就变为了情况a,然后使用情况a的方法,即可完成调整。
bool Insert(const pair<K, V>& data)
{
if (_head->_parent == nullptr)
{
Node* root = new Node(data);
_head->_parent = root;
_head->_left = _head->_right = root;
root->color = black;
root->_parent = _head;
return true;
}
Node* cur = _head->_parent;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (cur->_data.first == data.first)
{
return false;
}
if (cur->_data.first > data.first)
cur = cur->_left;
else
cur = cur->_right;
}
cur = new Node(data);
if (parent->_data.first > data.first)
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
//调整 : cur和parent都为红色,需要调整
while (cur != _head->_parent && cur->_parent->color == red)
{
Node* parent = cur->_parent;
Node* Gparent = parent->_parent;
//祖父节点的左孩子存在并且为红色
if (Gparent->_left == parent)
{
Node* uncle = Gparent->_right;
if (uncle && uncle->color == red)
{
uncle->color = parent->color = black;
Gparent->color = red;
cur = Gparent;
}
//如果cur = parent->right 左单旋一次
//cur = parent->left 右单旋一次 得到上面的情况 再做单旋一次即可
else
{
if (cur == parent->_right)
{
RotateLeft(parent);
swap(cur, parent);
}
RotateRight(Gparent);
parent->color = black;
Gparent->color = red;
break;
}
}
else
{
Node *uncle = Gparent->_left;
if (uncle && uncle->color == red)
{
uncle->color = parent->color = black;
Gparent->color = red;
cur = Gparent;
}
else
{
if (cur == parent->_left)
{
RotateRight(parent);
swap(cur, parent);
}
RotateLeft(Gparent);
parent->color = black;
Gparent->color = red;
break;
}
}
}
_head->_parent->color = black;
_head->_right = rightMost();
_head->_left = leftMost();
return true;
}
4.如何验证?
- 先验证是否满足搜索二叉树。
- 再验证是否满足红黑树的性质。
//判断是否是红黑树的条件:
//不能连续两个红色
//一个路径上黑色必须相同
//root 必须为黑色
bool IsRBTree()
{
Node* root = _head->_parent;
if (root == nullptr)
return true;
if (root->color == red)
return false;
Node* cur = root;
int BlackCout = 0;
while (cur)
{
if (cur->color == black)
BlackCout++;
cur = cur->_left; //找到一个基准值 然后遍历(前序)所有路径 如果都一样 则返回true
}
_IsRBTree(root, BlackCout, 0);
}
bool _IsRBTree(Node* root, int BlackCout, int NowCout)
{
if (root == nullptr)
{
if (BlackCout == NowCout)
return true;
return false;
}
if (root->color == black)
NowCout++;
if (root->color == red && root->_parent->color == red)
return false;
return _IsRBTree(root->_left, BlackCout, NowCout) && _IsRBTree(root->_right, BlackCout, NowCout);
}