一.RB-tree概述
红黑树是二叉平衡搜索树的一种,它确保了搜索时间的复杂度为O(logn),且其维护平衡所付出的代价小于AVL树,因为AVL树要求左右子树高度差最多为1,而红黑树通过一系列规则保证左右子树的高度差不超过2倍。
红黑树的规则如下:
1)每个节点不是红色就是黑色
2)根节点为黑色
3)如果节点为红,则其子节点必须为黑,这也就要求新增节点的父节点必须为黑,否则破坏平衡进行调节。
4)从任一节点起至NULL节点的任何路径,所含黑节点数必须相同。这也就要求每次新增的节点必为红。
红黑树便是通过规则3和规则4保证了左右子树的高度差不超过2倍,因为从任一节点到NULL节点的路径上黑节点数是相同的,设为n个,而红节点不可两两相连,因此最多是红黑相间,所以最多为n个,所以左右子树间的差值至多为2n / n = 2,即不超过两倍。
二.RB-tree的插入规则
新增节点必为红,而当新增节点的父节点也为红色时便违反了规则3,此时需要进行调整。红黑树的调整规则大的分类上可分为两种:在祖父节点的左子树中插入和在祖父节点的右子树中插入,其两者之间只是在某种情况下旋转的顺序反一下而已。每一种中又包含:伯父节点为黑和伯父节点为红。我们就以在祖父节点的左子树中插入为例
2.1 伯父节点为红
将父节点与伯父节点变黑,并将祖父节点变红,接着观察祖父节点与增祖父节点的关系是否违反规则,若违反则继续上推。若祖父系节点是根节点,则将祖父节点在变黑,之后退出。
【注】:祖父节点必为黑,因为若祖父节点为宏则父节点不可能为红,新增x也不会破坏规则了
2.2 伯父节点为黑
伯父节点为黑时又分为两种情况::新增节点为外侧插入和新增节点为内侧插入
1) 新增节点为外侧插入
此时先将父节点变黑,祖父节点变红,再以祖父节点为旋转点进行右旋:
2) 新增节点为内侧插入
先以父节点进行左旋(即旋转为了外侧插入的样子,只要记住了外侧插入就记住了内侧插入),再将新增节点变为黑,祖父节点变为红,最后以祖父节点为旋转点进行右旋
STL中关于旋转的代码如下:
// __x为新增节点,__root为根节点
inline void
_Rb_tree_rebalance(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root)
{
__x->_M_color = _S_rb_tree_red; // 新增节点的颜色必为红
while (__x != __root && __x->_M_parent->_M_color == _S_rb_tree_red) { // 若父节点非根节点,且父节点为红(说明违反规则)
if (__x->_M_parent == __x->_M_parent->_M_parent->_M_left) { // 若插入节点的父节点是祖父节点的左节点
_Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_right;
// - 若伯父节点为红节点则将父节点与伯父节点变黑,将增祖父节点变红。
// 再继续判断祖父节点与增祖父节点的关系,直至规则
//
// - 若伯父节点为黑节点且为内测插入则先以父节点为旋转点进行左旋
// 再将父节点变为黑,祖父节点变为红,最后以祖父节点为旋转点进行右旋
// 若不是内测插入则无需进行左旋步骤
if (__y && __y->_M_color == _S_rb_tree_red) { // 若伯父节点为红节点
__x->_M_parent->_M_color = _S_rb_tree_black;
__y->_M_color = _S_rb_tree_black;
__x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; // 当将某一子树的根节点由黑变为红时,为了保证黑节点的数量平等,必将其左右子节点变为黑
__x = __x->_M_parent->_M_parent; // 接着令__x指向伯父节点,继续上推。因为祖父节点变红后,增祖父节点可能也为红,需要继续调整
}
else {// 若伯父节点为黑节点(空也算黑节点)
if (__x == __x->_M_parent->_M_right) { // 若__x为内侧插入,即为父节点的右节点
__x = __x->_M_parent;
_Rb_tree_rotate_left(__x, __root); // 以父节点为旋转点进行左旋
}
__x->_M_parent->_M_color = _S_rb_tree_black;
__x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
_Rb_tree_rotate_right(__x->_M_parent->_M_parent, __root); // 以祖父节点为旋转点进行右旋,以保证黑节点的平衡
}
}
else { // 若插入节点的父节点是祖父节点的右节点(即处理时旋转顺序调换一下)
_Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_left;
if (__y && __y->_M_color == _S_rb_tree_red) {
__x->_M_parent->_M_color = _S_rb_tree_black;
__y->_M_color = _S_rb_tree_black;
__x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
__x = __x->_M_parent->_M_parent;
}
else {
if (__x == __x->_M_parent->_M_left) {
__x = __x->_M_parent;
_Rb_tree_rotate_right(__x, __root);
}
__x->_M_parent->_M_color = _S_rb_tree_black;
__x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
_Rb_tree_rotate_left(__x->_M_parent->_M_parent, __root);
}
}
}
__root->_M_color = _S_rb_tree_black; // 将根节点变为黑以满足规则。
}