红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
一、初步理解红黑树
1.基本性质
(1). 每个结点不是红色就是黑色
(2). 根节点是黑色的
(3). 如果一个节点是红色的,则它的两个孩子结点是黑色的
(4). 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
(5). 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
2.红黑树的节点结构
template<class T>
struct RBTreeNode
{
typedef RBTreeNode<T> Node;
Node* _parent;
Node* _left;
Node* _right;
colour _col;
T _data;
RBTreeNode(const T& data)
:_parent(nullptr)
, _left(nullptr)
, _right(nullptr)
, _col(RED)
, _data(data)
{
}
};
二、红黑树的插入
因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:
可以总结以上情况为:
1.父亲节点为黑,则不需要处理。
2.父亲节点为红且uncle节点存在且为红,只需要grand变红,uncle和parent变黑继续向上讨论即可。
3.父亲节点为红且uncle为黑色或者不存在,需要旋转加变色,旋转的情况需要讨论:如果grand节点、parent节点、cur节点在同一侧则只单旋,parent变黑,grand变红;反之则需要双旋,cur变黑,grand变红。以下为红黑树插入代码C++实现。
bool insert(const T& data)
{
KeyOfT kot;//提取key值的仿函数对象
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return true;
}
Node* cur = _root, * parent = nullptr;
while (cur)
{
if (kot(data) > kot(cur->_data))
{
parent = cur;
cur = cur->_right;
}
else if (kot(data) < kot(cur->_data))
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(data);
if (kot(parent->_data) > kot(data))
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* pparent = parent->_parent;
if (pparent->_left == parent)
{
Node* uncle = pparent->_right;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
pparent->_col = RED;
cur = pparent;
parent = cur->_parent;
}
else
{
if (parent->_left == cur)
{
RevolveR(pparent);
parent->_col = BLACK;
pparent->_col = RED;
}
else
{
RevolveL(parent);
RevolveR(pparent);
cur->_col = BLACK;
pparent->_col = RED;
}
break;
}
}
else
{
Node* uncle = pparent->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
pparent->_col = RED;
cur = pparent;
parent = cur->_parent;
}
else
{
if (parent->_right == cur)
{
RevolveL(pparent);
parent->_col = BLACK;
pparent->_col = RED;
}
else
{
RevolveR(parent);
RevolveL(pparent);
cur->_col = BLACK;
pparent->_col = RED;
}
break;
}
}
_root->_col = BLACK;
}
return true;
}