RB-tree
红黑树比AVL树的优势 https://blog.csdn.net/mmshixing/article/details/51692892RB-tree不仅是一个二叉搜索树,而且必须满足一些规则:
每个节点不是红色就是黑色(图中深色代表黑,浅色代表红)
根节点为黑色
如果节点为红,其子节点必须为黑
任一节点至NULL(树尾端)的任何路径,所含之黑节点数必须相同
根据规则4,新增节点不许为红;根据规则3,新增节点之父节点必须为黑。当新节点根据二叉搜索树的规则到达其插入点,却未能符合上述条件时,就必须调整颜色并旋转树形。
插入节点
在图5-13的RB-tree分别插入3,8,35,75,根据二叉搜索树的规则,这四个新节点落脚处应如图5-14所示,它们破坏了RB-tree的规则,因此必须调整树形,也就是旋转树形并改变节点颜色。
假设新节点为X,其父节点为P,祖父节点为G,伯父节点(父节点的兄弟节点)为S,曾祖父节点为GG
状况1:S为黑且X为外侧插入。对此情况,先对P,G做一次单选转,再更改P,G颜色,即可重新满足红黑树的规则3。
状况2:S为黑且X为内测插入。对此情况,必须现对P,X做一次单选转并更改G,X颜色,再将结果对G做一次单选转,即可再次满足红黑树规则3。
状况3:S为红且X为外侧插入。对此情况,现对P和G做一次单选转,并改变X的颜色。此时如果GG为黑,一切搞定,但如果GG为红,则问题比较大,见状况4。
状况4:S为红且X为外侧插入。对此情况,先对P和G做一次单选转,并改便X的颜色。此时如果GG也为红。害的持续网上做,直到不再有父子连续为红的情况。
一个自上而下的程序
为避免插入节点的情况4,可以用自顶向下的方法:假设新增节点为A,就顺着A的路径,当遇到一个节点X的两个儿子都为红,就将X改为红,两个儿子改为黑。当X的父节点也为红使用情况1或情况2中的方法做调整。
RB-tree的节点设计
RB-tree有红黑二色,并且拥有左右子节点,很容易勾勒出其结构风貌。下面是SGI STL的实现源码。为了有更大的弹性,节点分为两层。
由于RB-tree的各种操作时常需要上溯其父节点,所以特别在数据结构中安排了一个parent指针。
typedef bool __rb_tree_color_type; const __rb_tree_color_type __rb_tree_red = false; // 红色为0 const __rb_tree_color_type __rb_tree_black = true; // 黑色为1 struct __rb_tree_node_base { typedef __rb_tree_color_type color_type; typedef __rb_tree_node_base* base_ptr; color_type color; // 节点颜色,红色或黑色 base_ptr parent; // 该指针指向其父节点 base_ptr left; // 指向左节点 base_ptr right; // 指向右节点 static base_ptr minimum(base_ptr x) { while (x->left != 0) x = x->left; //一直向左走,找到最小值 return x; } static base_ptr maximum(base_ptr x) { while (x->right != 0) x = x->right; //一直向右走,找到最大值 return x; } }; template <class Value> struct __rb_tree_node : public __rb_tree_node_base { typedef __rb_tree_node<Value>* link_type; Value value_field; //节点值 };
RB-tree的迭代器
SGI将RB-tree迭代器实现分为两层。图5-16是两层节点结构和双层迭代器结构间的关系,其中主要意义是: _ rb_tree_node 继承自 rb_tree_node_base ,rb_tree_iterator继承自_rb_tree_base_iterator。
RB-tree的元素操作