目录
一、红黑树的定义
红黑树是一棵二叉搜索树,每个节点上增加一个存储位来表示结点的颜色
通过对任何一个从根到叶子结点的路径上各个节点的颜色进行约束,
红黑树确保没有一条路径会比其他路径长出二倍,因此接近平衡
(最长路径不超过最短路径的二倍)
二、红黑树的规则
1、每个节点不是红色就是黑色
2、根节点必须是黑色
3、如果一个节点是红色的,那么他的两个孩子节点必须是黑色的
也就是说任意一条路径不会有连续的红色节点(黑色节点的孩子红黑均可)
4、对于任意一个节点,从该节点到其所有NULL节点的简单路径上,都具有相同数量多黑色节点
(一条路径走到空节点才算走完,走到叶子节点不算走完)
假设每条路径有X和黑色节点
理论上最长路径:X,全黑;最短路径:2 * X,一黑一红
有的时候为了方便表示出路径,会将所有叶子结点的空节点都令其为黑色节点
并命名为NIL,并称所有叶子结点都是黑色节点(并不是传统的叶子结点)
三、红黑树的效率:
假设每个路径有h个黑色节点,则总结点个数为2^h - 1 <= N < 2^(2h) - 1
所以h≈logN,即使是最坏情况也只是2*logN,因此时间复杂度是O(logN)
四、红黑树的插入
1、对于空的红黑树而言,我们令根节点为黑色,方便满足规则四
2、对于非空红黑树而言,我们插入的节点为红色,因为一旦插入黑色会导致原来黑色节点数量相等的各个路径不在相等,难以调整,因此我们选择插入红色节点;但是红色节点也可能会存在问题,即出现红色节点连续的情况,不满足规则三
3、因此在找到要插入的节点的parent(p)节点之后,如果p节点是黑节点,则不会破坏规则,但如果是红色节点,则需要进行调整
4、这里已经确定了parent节点为红,current(c)节点为红,grandfather(g)节点为黑,不确定的只有uncle(u)节点的情况
grandfather
parent uncle
current 注:仅为示意图
5、既然只有uncle不确定,那么就以uncle为判断标准进行分类讨论:
但还有两种大的情况,即parent节点是在grandfather节点的左还是右;其中每种情况又可以分为以下情况
(1)uncle存在且为红色节点,这时,为了满足规则三和规则四,只需让uncle和parent变为黑色,让grandfather变为红色,这样保证了各个路径黑色节点数目不变;但是还存在新的问题,即g节点的p节点可能是红色的,有不满足规则三,所以还需要继续更新,让c指向g,更新p、u、g
(2)uncle不存在或者存在且为黑色,这时需要旋转,如果出现折线,需要双旋
grandfather(黑)
parent(红) uncle(黑色或不存在)
cur(红)
↓
parent(黑)
cur (红) grandfather(红)
uncle(黑)
ps.这里仅为右单旋示意图(因为是省略图,所以这里每条路径黑色节点数量并不相等,事实上cur的子树里还有黑色节点,整棵树的规则四不受影响)
grandfather(黑)
parent(红) uncle(黑)
cur(红)
↓
grandfather(黑)
cur(红) uncle(黑)
parent(红)
↓
cur(黑)
parent(红) grandfather(红)
uncle(黑)
ps.这里仅为左右单旋示意图(因为是省略图,所以这里每条路径黑色节点数量并不相等,事实上cur的子树里还有黑色节点,整棵树的规则四不受影响)
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
cur->_col = RED;
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
// g
// p u
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED; cur = grandfather;
parent = cur->_parent;
}
else {
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// u p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}