红黑树
红黑树的概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。
红黑树的性质
1.每个节点不是黑色就是红色
2.根节点是黑色的
3.如果一个节点是红色的,那么它的两个孩子节点是黑色的
4.对于每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
5.每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
红黑树节点的定义
enum Colour
{
RED,//红色
BLACK//黑色
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
,_kv(kv)
,_col(RED)//默认的新节点都是红色的
{}
};
红黑树的插入操作
红黑树的插入可以分为两步:
1.按照二叉搜索树的规则插入新节点
2.检测新节点插入后,红黑树的性质是否遭到破坏,若是则调整红黑树
新节点的默认颜色是红色,若双亲节点是黑色,则没有违反红黑树的规则,无需调整;若双亲节点颜色为红色时,就违反了不能有连在一起的红色节点这个规则,此时要分类讨论。
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
情况一: cur为红,p为红,g为黑,u存在且为红
解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
情况二:cur为红,p为红,g为黑,u不存在/u存在且为黑
说明:
若u节点不存在,则cur一定是心插入节点,因为如果cur不是新插入节点,则cur和p一定有一个节点的颜色是黑色,就不满足每条路径黑色节点个数相同。
若u节点存在,则其一定是黑色的,那么cur节点原来的颜色一定是黑色的,现在看到的红色是因为cur的子树在调整过程中把cur从黑色改成了红色。
解决方式:
p为g的左孩子,cur为p的左孩子,则进行右单旋转;
p为g的右孩子,cur为p的右孩子,则进行左单旋转;
p、g变色,p变黑,g变红
情况三:cur为红,p为红,g为黑,u不存在/u存在且为黑
这种情况就需要双旋,先单旋转换为情况二,再进行一次旋转
//插入
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->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;//插入节点不能重复
}
}
//插入新节点
cur = new Node(kv);//红色的
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;//爷爷节点
//父节点在爷爷节点的左边,那么叔叔节点在右边
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
grandfather->_col = RED;
uncle->_col = parent->_col = BLACK;
cur = grandfather;//爷爷不是根,向上更新
parent = cur->_parent;
}
//情况二:叔叔不存在/存在且为黑
else
{
//单旋
if (cur == parent->_left)
{
RotateR(grandfather);//右单旋
parent->_col = BLACK;//变色
grandfather->_col = RED;
}
//左右双旋
// cur == parent->_right
else
{
RotateL(parent);//先左单旋
RotateR(grandfather);//再右单旋
grandfather->_col = RED;//变色
cur->_col = BLACK;
}
}
}
else//父节点在右边,叔叔在左边
{
Node* uncle = grandfather->_left;
//情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
grandfather->_col = RED;
uncle->_col = parent->_col = BLACK;
cur = grandfather;//爷爷不是根,向上更新
parent = cur->_parent;
}
//情况二:叔叔不存在/存在且为黑
else
{
//单旋
if (cur == parent->_right)
{
RotateL(grandfather);//左单旋
parent->_col = BLACK;//变色
grandfather->_col = RED;
}
//右左双旋
// cur == parent->_left
else
{
RotateR(parent);//先右单旋
RotateL(grandfather);//再左单旋
grandfather->_col = RED;//变色
cur->_col = BLACK;
}
break;//经过情况二后跳出
}
}
}
_root->_col = BLACK;//统一处理,根必须是黑的
return true;
}
//左单旋
void RotateL(Node* parent)
{
RotateSize++;
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
//不为空
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = subR;
//处理parent如果为根
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
//不为根,处理与ppnode的连接
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
}
//右单旋
void RotateR(Node* parent)
{
RotateSize++;
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
//不为空
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
Node* ppnode = parent->_parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subL;
}
else
{
ppnode->_right = subL;
}
subL->_parent = ppnode;
}
}