红黑树
与上一篇文章说的AVL树类似,红黑树也是一种可以平衡高度的搜索树,不同点在于红黑树通过控制节点的颜色来调节搜索树的高度。
红黑树的性质
1.每个节点不是红色就是黑色
2.根节点是黑色的
3.不能有连续的红色节点
4.对于每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
5.每个叶子节点都是黑色的(这里的叶子节点指的是空节点)
当满足这些性质时,就可以保证红黑树中最长路径高度不超过最短路径的两倍。我们可以想象在红黑树中每条路径黑色节点的数量都是相同的,那么最长路径一定是红黑交替存在的路径,而最短路径一定是全黑的路径,此时最长路径高度为最短路径的两倍。
节点结构
enum Colour
{
// 红黑树颜色
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _parent;//父节点
RBTreeNode<T>* _left;//左节点
RBTreeNode<T>* _right;//右节点
T _data;//数据
Colour _col;//颜色
RBTreeNode(const T& data)
:_parent(nullptr)
, _left(nullptr)
, _right(nullptr)
, _col(RED)
, _data(data)
{}
};
插入规则
与上一篇AVL树插入规则相似,先按照搜索树的规则插入,我们每次先将要插入的节点设为红色,当节点插入到合适的位置后,我们检查节点的父节点是否为红色,如果父节点为黑色,那么插入直接成功,如果父节点为红色,则不符合规则三,需要调整颜色。红黑树的调整比AVL树简单很多,我们只需要关注其叔叔节点(父节点的兄弟节点)即可,下面是我列举的各种情况。
我们可以把情况大致分为两种
1.叔叔节点存在且为红色
2.叔叔节点存在且为黑或不存在
本能反应告诉我们第一种状态一定是更均衡的,因为此时父亲和叔叔节点的颜色都为红色,因此对他们的操作也符合我们的本能反应,
- 对于第一种情况我们要将父节点和叔叔节点的颜色变为黑,并将祖父节点变为红色,并从祖父节点开始继续向上调整
- 对与第二种情况我们需要对该树进行旋转(旋转可以使树趋向平衡)
这就是红黑树插入操作最核心的思想,接下来我们来看看插入操作的细节
插入操作实现细节
pair<iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
KeyOfT kot;
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (kot(data) > kot(cur->_data))
{
cur = cur->_right;
}
else if (kot(data) < kot(cur->_data))
{
cur = cur->_left;
}
else
{
return make_pair(iterator(cur), false);
}
}
cur = new Node(data);
Node* NewNode = cur;
cur->_parent = parent;
if (kot(data) > kot(parent->_data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
while (parent && parent->_col == RED)
{
Node* grandparent = parent->_parent;
if (parent == grandparent->_left)
{
Node* uncle = grandparent->_right;
if (uncle && uncle->_col == RED)
{
uncle->_col = parent->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else // 叔叔存在且为黑或叔叔不存在
{
if (cur == parent->_left)
{
RotateR(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
else
{
RotateL(parent);
RotateR(grandparent);
cur->_col = BLACK;
grandparent->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandparent->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
RotateL(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
else
{
RotateR(parent);
RotateL(grandparent);
cur->_col = BLACK;
grandparent->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(NewNode), false);
}