下面节选自STL源码剖析,简体是我的注释
rb tree的自增和自减内部函数,自增或者自减寻找的是中序后继和中序前继
void increment()
{
if (node->right != 0) { // 如果有右子節點。狀況(1)
node = node->right; // 就向右走
while (node->left != 0) // 然後一直往左子樹走到底
node = node->left; // 即是解答
}
else { // 沒有右子節點。狀況(2)
base_ptr y = node->parent; // 找出父節點,上溯
while (node == y->right) { // 如果現行節點本身是個右子節點,
node = y; // 就一直上溯,直到「不為右子節點」止。我的理解:如果上溯是右枝,表明是往前找,如果是左枝,表示往后
y = y->parent;
}
if (node->right != y) // 「若此時的右子節點不等於此時的父節點」。
node = y; // 狀況(3) 此時的父節點即為解答。
// 否則此時的node 為解答。狀況(4)
}
// 注意,以上判斷「若此時的右子節點不等於此時的父節點」,是為了應付一種
// 特殊情況:我們欲尋找根節點的下一節點,而恰巧根節點無右子節點。
// 當然,以上特殊作法必須配合 RB-tree 根節點與特殊之header 之間的
// 特殊關係。
}
// 以下其實可實作於 operator-- 內,因為再無他處會呼叫此函式了。
void decrement()
{
if (node->color == __rb_tree_red && // 如果是紅節點,且
node->parent->parent == node) // 父節點的父節點等於自己,
node = node->right; // 狀況(1) 右子節點即為解答。
// 以上情況發生於node為header時(亦即 node 為 end() 時)。
// 注意,header 之右子節點即 mostright,指向整棵樹的 max 節點。
else if (node->left != 0) { // 如果有左子節點。狀況(2)
base_ptr y = node->left; // 令y指向左子節點
while (y->right != 0) // 當y有右子節點時
y = y->right; // 一直往右子節點走到底
node = y; // 最後即為答案
}
else { // 既非根節點,亦無左子節點。
base_ptr y = node->parent; // 狀況(3) 找出父節點
while (node == y->left) { // 當現行節點身為左子節點
node = y; // 一直交替往上走,直到現行節點
y = y->parent; // 不為左子節點,理解:一直找到不为左枝的父节点,即为前继节点
}
node = y; // 此時之父節點即為答案
}
}
// 新節點必為紅節點。如果安插處之父節點亦為紅節點,就違反紅黑樹規則,此時必須
// 做樹形旋轉(及顏色改變,在程式它處)。
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
// x 為旋轉點
__rb_tree_node_base* y = x->right; // 令y 為旋轉點的右子節點
x->right = y->left;
if (y->left !=0)
y->left->parent = x; // 別忘了回馬槍設定父節點
y->parent = x->parent;
// 令 y 完全頂替 x 的地位(必須將 x 對其父節點的關係完全接收過來)
if (x == root) // x 為根節點
root = y;
else if (x == x->parent->left) // x 為其父節點的左子節點
x->parent->left = y;
else // x 為其父節點的右子節點
x->parent->right = y;
y->left = x;
x->parent = y;
}
// 新節點必為紅節點。如果安插處之父節點亦為紅節點,就違反紅黑樹規則,此時必須
// 做樹形旋轉(及顏色改變,在程式它處)。
inline void
__rb_tree_rotate_right(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
// x 為旋轉點
__rb_tree_node_base* y = x->left; // y 為旋轉點的左子節點
x->left = y->right;
if (y->right != 0)
y->right->parent = x; // 別忘了回馬槍設定父節點
y->parent = x->parent;
// 令 y 完全頂替 x 的地位(必須將 x 對其父節點的關係完全接收過來)
if (x == root) // x 為根節點
root = y;
else if (x == x->parent->right) // x 為其父節點的右子節點
x->parent->right = y;
else // x 為其父節點的左子節點
x->parent->left = y;
y->right = x;
x->parent = y;
}
template //一大堆的模板参数
typename rb_tree::iterator //返回rb_tree的迭代器
rb_tree::
__insert(base_ptr x_, base_ptr y_, const Value& v) { //x为新位置,y是安插位置父节点,v是模板参数值,是实际内容
// 參數x_ 為新值安插點,參數y_ 為安插點之父節點,參數v 為新值。
link_type x = (link_type) x_;
link_type y = (link_type) y_;
link_type z;
// key_compare 是鍵值大小比較準則。應該會是個 function object。
if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) { //【如果父节点为header,表明是空树;x!=0 未知;key_compare,v比y小则true;】
z = create_node(v); // 產生一個新節點
left(y) = z; // 這使得當 y 即為 header時,leftmost() = z //【z放置于y的左子树,因为比y小】
if (y == header) { //【空树处理】
root() = z;
rightmost() = z;
}
else if (y == leftmost()) // 如果y為最左節點,更新最左域
leftmost() = z; // 維護leftmost(),使它永遠指向最左節點
}
else {
z = create_node(v); // 產生一個新節點
right(y) = z; // 令新節點成為安插點之父節點 y 的右子節點
if (y == rightmost())
rightmost() = z; // 維護rightmost(),使它永遠指向最右節點
}
parent(z) = y; // 設定新節點的父節點
left(z) = 0; // 設定新節點的左子節點
right(z) = 0; // 設定新節點的右子節點
// 新節點的顏色將在 __rb_tree_rebalance() 設定(並調整)
__rb_tree_rebalance(z, header->parent); // 參數一為新增節點,參數二為 root (【最复杂的部分,调整红黑树,使得满足红黑树性质】)
++node_count; // 節點數累加
return iterator(z); // 傳回一個迭代器,指向新增節點
}
红黑树插入balance调整 (父节点为祖父节点的左右子树各3种cases)
// 重新令樹形平衡(改變顏色及旋轉樹形)
// 參數一為新增節點,參數二為 root
inline void
__rb_tree_rebalance(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
x->color = __rb_tree_red; // 新節點必為紅,新插入节点全设置为红色
while (x != root && x->parent->color == __rb_tree_red) { // 父節點為紅,如果父节点为黑色或者新插入节点为根(只需将新插入的根变色为黑色),则满足红黑性质
if (x->parent == x->parent->parent->left) { // 父節點為祖父節點之左子節點, 【处理父节点是祖父节点的左子树的情况】
__rb_tree_node_base* y = x->parent->parent->right; // 令y 為伯父節點
if (y && y->color == __rb_tree_red) { // 伯父節點存在,且為紅 【 Case 1, 叔父节点同为红色】
x->parent->color = __rb_tree_black; // 更改父節點為黑
y->color = __rb_tree_black; // 更改伯父節點為黑
x->parent->parent->color = __rb_tree_red; // 更改祖父節點為紅
x = x->parent->parent; //【转向祖父节点,继续进行红黑调整】
}
else { // 無伯父節點,或伯父節點為黑
if (x == x->parent->right) { // 如果新節點為父節點之右子節點 【Case 2,插入节点是父节点的右子树,调整为左子树情况】
x = x->parent;
__rb_tree_rotate_left(x, root); // 第一參數為左旋點
}
x->parent->color = __rb_tree_black; // 改變顏色 【Case 3, 插入节点为父节点左子树情况,父节点变黑,祖父节点变红,右旋】
x->parent->parent->color = __rb_tree_red;
__rb_tree_rotate_right(x->parent->parent, root); // 第一參數為右旋點,【注意是以祖父节点为轴右旋】
}
}
else { // 父節點為祖父節點之右子節點 【处理父节点是祖父节点的右子树的情况】
__rb_tree_node_base* y = x->parent->parent->left; // 令y 為伯父節點
if (y && y->color == __rb_tree_red) { // 有伯父節點,且為紅 【 Case 1】
x->parent->color = __rb_tree_black; // 更改父節點為黑
y->color = __rb_tree_black; // 更改伯父節點為黑
x->parent->parent->color = __rb_tree_red; // 更改祖父節點為紅
x = x->parent->parent; // 準備繼續往上層檢查...
}
else { // 無伯父節點,或伯父節點為黑
if (x == x->parent->left) { // 如果新節點為父節點之左子節點 【Case 2, 节点,父节点和祖父节点不在一条线上】
x = x->parent;
__rb_tree_rotate_right(x, root); // 第一參數為右旋點
}
x->parent->color = __rb_tree_black; // 改變顏色 【 Case 3, 一条直线上的情况,父节点变黑,祖父变红,祖父节点左旋】
x->parent->parent->color = __rb_tree_red;
__rb_tree_rotate_left(x->parent->parent, root); // 第一參數為左旋點
}
}
} // while 結束
root->color = __rb_tree_black; // 根節點永遠為黑 【 最后别忘了置根颜色为黑色,因为前面没有处理插入点为根的情况】
}
template
inline void
rb_tree::erase(iterator position) {
link_type y = (link_type) __rb_tree_rebalance_for_erase(position.node, //【直接调用delete re-balance,因为不用寻找删除点】
header->parent,
header->left,
header->right);
destroy_node(y); //【销毁节点】
--node_count; //【节点数更新】
}
红黑树删除的balance操作,非常复杂(左右子树各4种主要cases,外加一点额外的其他情况)
inline __rb_tree_node_base* //返回删除的红黑树的节点指针
__rb_tree_rebalance_for_erase(__rb_tree_node_base* z, //删除点
__rb_tree_node_base*& root, //根
__rb_tree_node_base*& leftmost, //最左点,如果删除点正是最左点,需要更新最左点
__rb_tree_node_base*& rightmost) //最右点,同上
{
__rb_tree_node_base* y = z;
__rb_tree_node_base* x = 0; //用x表示后续节点,来代替删除点
__rb_tree_node_base* x_parent = 0;
if (y->left == 0) // // 如果删除点没有左子树
x = y->right; // 那么选右子树来替换,注意,对于没有左右子树的节点来说,x可能为空,不过无所谓
else
if (y->right == 0) // 如果左子树不空,但是右子树为空,则选右子树为替代者
x = y->left; // x is not null.
else { // 如果左右子树都不空,那么需要寻找删除节点的中序后继节点来替换
y = y->right; // 也就是找右子树的“最左下节点”.
while (y->left != 0) //一直往左找
y = y->left; //y为右子树上的最小值,注意这个节点,必然【只有一个右孩子,或者没有右孩子】,因为他是右子树上的最小值!!!
x = y->right; //找到后,x即为删除点的“后”节点,将用来替换y节点
}
if (y != z) { //如果y!=z表示,后继节点情况,直接
z->left->parent = y; //将z的左子树变成y的左子树
y->left = z->left;
if (y != z->right) { //如果y不是z的右孩子,【注意,整个过程实际上是将节点z用y替换的过程(一般直接用值copy就可以了,呵呵)】
x_parent = y->parent; //暂取y的父节点
if (x) x->parent = y->parent; //如果x不为空,即,y的右子树不为空,则x的父节点转成y的父节点
y->parent->left = x; // 将x挂到y的父节点的左子树上
y->right = z->right; //z的右子树成为y的右子树
z->right->parent = y;
}
else
x_parent = y;
if (root == z) //如果删除点是根节点,则root变成y ,y是z的中序后继节点
root = y;
else if (z->parent->left == z) //否则如果z为左枝,则将y挂到左枝
z->parent->left = y;
else
z->parent->right = y; //z为右枝,则y挂到右枝
y->parent = z->parent; //变换y的父节点为z的父节点
__STD::swap(y->color, z->color); //替换y和z的颜色!!!
y = z; //现在指向即将被删除的z节点
// y now points to node to be actually deleted
}
else { // y == z // y == z 【以下是对y不是后继节点的情况】
x_parent = y->parent;
if (x) x->parent = y->parent;
if (root == z) //z为根,则子节点x为新的根
root = x;
else
if (z->parent->left == z) //否则孩子节点x将对应删除节点的左枝或者右枝
z->parent->left = x;
else
z->parent->right = x;
if (leftmost == z)
if (z->right == 0) // z->left must be null also
leftmost = z->parent; //如果z是最小,最左节点,则更新最左节点为z的父节点,因为z的父节点恰好比z大一点,是z的中序后继
// makes leftmost == header if z == root
else
leftmost = __rb_tree_node_base::minimum(x); //否则计算x为根的最左
if (rightmost == z)
if (z->left == 0) // z->right must be null also
rightmost = z->parent;
// makes rightmost == header if z == root
else // x == z->left
rightmost = __rb_tree_node_base::maximum(x); //最右更新同理
} //【以下是真正复杂的删除后调整】
if (y->color != __rb_tree_red) { //仅仅如果删除的节点为黑色,才会触发调整动作
while (x != root && (x == 0 || x->color == __rb_tree_black)) //如果x是根,或者x的颜色为黑色,或者x为空,则结束调整
if (x == x_parent->left) { //【删除节点为父节点的左子树情况讨论】
__rb_tree_node_base* w = x_parent->right; //兄弟节点w
if (w->color == __rb_tree_red) { // 【case 1,兄弟节点为红色】
w->color = __rb_tree_black; //调整兄弟节点为黑色,父节点为红色,以父节点为轴进行左旋,调整为其他case
x_parent->color = __rb_tree_red;
__rb_tree_rotate_left(x_parent, root);
w = x_parent->right; //更新旋转之后的兄弟节点
}
if ((w->left == 0 || w->left->color == __rb_tree_black) &&
(w->right == 0 || w->right->color == __rb_tree_black)) {//【case 2,如果兄弟节点左右子树为全黑色,可以认为空表示黑色】
w->color = __rb_tree_red; //变换非空兄弟的颜色为红色,转而以父节点为x调整父节点红黑特性
x = x_parent;
x_parent = x_parent->parent;
} else { //【case 3, 如果兄弟节点右孩子为黑色,但是左孩子为红色】
if (w->right == 0 || w->right->color == __rb_tree_black) {
if (w->left) w->left->color = __rb_tree_black; //调整左孩子颜色为黑色
w->color = __rb_tree_red; //调整兄弟节点为红色
__rb_tree_rotate_right(w, root); //以兄弟节点为轴,右旋兄弟节点和左孩子,转换case 3为case 4
w = x_parent->right;
} //【case 4, 如果兄弟节点右孩子为红色,不管左孩子颜色】
w->color = x_parent->color; //右孩子颜色变黑,兄弟节点变成原父节点的颜色,原父节点变黑
x_parent->color = __rb_tree_black;
if (w->right) w->right->color = __rb_tree_black;
__rb_tree_rotate_left(x_parent, root); //以父节点为轴,进行左旋
break; //case 4的调整完后,就可以满足红黑特性了,可以直接退出了
}
} else { // //如果删除节点为父节点的右孩子的情况,跟上面的左孩子情况对应.
__rb_tree_node_base* w = x_parent->left; //左兄弟节点w
if (w->color == __rb_tree_red) { //【case 1, 兄弟节点为红的情况,变父节点为红,变兄弟节为黑,父节点为轴左旋,转换为后面的几种case】
w->color = __rb_tree_black;
x_parent->color = __rb_tree_red;
__rb_tree_rotate_right(x_parent, root);
w = x_parent->left; //更新新的兄弟节点
}
if ((w->right == 0 || w->right->color == __rb_tree_black) &&
(w->left == 0 || w->left->color == __rb_tree_black)) { //【case 2, 兄弟节点的左右子树均为黑,空认为是黑色】
w->color = __rb_tree_red; //兄弟节点变红
x = x_parent; //上溯到父节点继续进行红黑平衡
x_parent = x_parent->parent;
} else {
if (w->left == 0 || w->left->color == __rb_tree_black) { //【case 3,兄弟节点w的左子树为黑,右子树为红】
if (w->right) w->right->color = __rb_tree_black; //变兄弟节点w的左子树为红,右子树为黑
w->color = __rb_tree_red;
__rb_tree_rotate_left(w, root); //以兄弟节点为轴,进行左旋
w = x_parent->left; //更新新的兄弟节点,转换成case 4的情况
}
w->color = x_parent->color; //【case 4,兄弟节点w的左子树为红,右子树无所谓】变兄弟节点为原父节点颜色
x_parent->color = __rb_tree_black; //父节点变黑,兄弟节点w的红色左孩子变黑
if (w->left) w->left->color = __rb_tree_black;
__rb_tree_rotate_right(x_parent, root); //以父节点为轴,进行右旋
break; //case 4变换之后,就可以满足红黑特性了,直接退出调整
}
}
if (x) x->color = __rb_tree_black; //最后调整x,如果x为红色节点,直接变黑就可以满足条件了,上面调整的都是x原本就是黑色的情况
}
return y;
}