RB-tree的数据结构
下面是rb-tree的定义。你可以看到其中定义有专属的空间配置器,每次用来配置一个节点的大小,也可以看到各种型别定义,用来维护整颗RB-tree的三笔数据(其中有个仿函数,functor,用来表现节点的大小比较方式),以及一些member function的定义或声明。
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
class rb_tree {
protected:
typedef void* void_pointer;
typedef __rb_tree_node_base* base_ptr;
typedef __rb_tree_node<Value> rb_tree_node;
typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
typedef __rb_tree_color_type color_type;
public:
typedef Key key_type;
typedef Value value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef rb_tree_node* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
link_type get_node() { return rb_tree_node_allocator::allocate(); }
void put_node(link_type p) { rb_tree_node_allocator::deallocate(p); }
link_type create_node(const value_type&x) {
link_type tmp = get_node();
__STL_TRY {
construct(&tmp->value_field, x);
}
__STL_UNWIND(put_node(tmp));
return tmp;
}
link_type clone_node(link_type x) {
link_type tmp = create_node(x->value_field);
tmp->color = x->color;
tmp->left = 0;
tmp->right = 0;
return tmp;
}
void destroy_node(link_type p) {
destroy(&p->value_field);
put_node(p);
}
protected:
size_type node_count; // 追踪记录树的大小
link_type header; // 实现小技巧
Compare key_compare; // 节点间键值大小比较function
link_type& root() const { return (link_type&) head->parent;}
link_type& leftmost() const { return (link_type&) head->left; }
link_type& rightmost() const { return (link_type&) head->right; }
static link_type& left(link_type x)
{ return (link_type&) (x->left); }
static link_type& right(link_type x)
{ return (link_type&) (x->right); }
static link_type& parent(link_type x)
{ return (link_type&) (x->parent); }
static reference value(link_type x)
{ return x->value_field; }
static Key& key(link_type x)
{ return KeyOfValue()value(x); }
static color_type& color(link_type x)
{ return (color_type&)(x->color); }
static link_type minimum(link_type x) {
return (link_type) __rb_tree_node_base::minimum(x);
}
static link_type maximum(link_type x) {
return (link_type) __rb_tree_node_base::maximum(x);
}
public:
typedef __rb_tree_iterator<value_type, reference, pointer> iterator;
private:
iterator __insert(base_ptr x, base_ptr y, count value_type& v);
link_type __copy(link_type x, link_type p);
void __erase(link_type x);
void init() {
header = get_node();
color(header) = __rb_tree_red;
root() = 0;
leftmost() = header;
rightmost() = header();
}
public:
rb_tree(const Compare& comp = Compare())
: node_count(0), key_compare(comp) {
init();
}
~rb_tree() {
clear();
put_node(header);
}
rb_tree<Key, Value, KeyOfValue, Compare, Alloc> &
operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&x);
public:
Compare key_comp() const { return key_compare; }
iterator begin() { return leftmost(); }
iterator end() { return header; }
bool empty() const { return node_count == 0; }
size_type size() const { return node_count; }
size_type max_size() const { return size_type(-1); }
public :
parir<iterator, bool> insert_unique(const value_type&x);
iterator insert_equal(const value_type&x);
...
};
RB-tree的构造与内存管理
下面是RB-tree所定义的专属空间配置器rb_tree_node_allocator,每次可恰恰配置一个节点。它所使用的simple_alloc<>是STL中使用的内存分配器(后续补充其定义)
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
class rb_tree {
protected:
typedef void* void_pointer;
typedef __rb_tree_node_base* base_ptr;
typedef __rb_tree_node<Value> rb_tree_node;
typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
...
};
先前所列的程序片段也显示了数个节点相关函数如get_node(),put_node(),create_node(),clone_node(),destroy_node()。
RB-tree的构造方式有两种,一种是以现有的RB-tree复制一个新的RB-tree,另一种是产生一颗空空如也得树,如下所示:
rb_tree<int, int, identity<int>, less<int> >itree;
这行程序代码分别指定了节点的键值、实值、大小比较标准...然后调用RB-tree的default constructor:
rb_tree(const Compare& comp = Compare())
: node_count(0), key_compare(comp) { init(); }
其中init()是实现技巧上的一个关键点:
private:
void init() {
header = get_node();
color(header) = __rb_tree_red;
root() = 0;
leftmost() = header;
rightmost() = header;
}
我们知道,树形结构的各种操作,最需要注意的就是边界情况的发生,也就是走到根节点时需要有特殊的处理。为了简化处理,SGI STL特别为根节点再设计一个父节点,名为header,并另其初其初始状态如下图所示;插入节点后,header的left和right,分别指向最小的begin()和最大的元素。
RB-tree的元素操作
本节主要只谈元素(节点)的插入和搜寻。RB-tree提供两种插入操作:insert_unique()和insert_equal(),前者表示被插入节点的键值(key)在整颗树中必须独一无二,后者表示被插入节点的键值在整颗树中可以重复,因此,无论如何插入都会成功(除非空间不足)。这个两个函数都有数个版本,以下以最简单的版本作为说明对象。注意,虽然只指定实值,但RB-tree一开始即要求用户必须明确设定所谓的KeyOfValue仿函数,因此,从实值中取出键值key是毫无问题的。
元素插入操作insert_equal()
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Allloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_equal(const Value &v) {
link_type y = header;
link_type x = root();
while (x != 0) {
y = x;
x = key_compare(KeyOfValue()(v), key(x)) ? left(x) : right(x);
}
return __insert(x, y, v);
}
元素插入操作insert_unique()
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_unque(const Value&v) {
link_type y = header;
link_type x = root();
bool compare = true;
while(x 1= 0) {
y = x;
comp = key_compare(KeyOfValue()(v), key(x));
x = comp ? left(x) : right(x);
}
iterator j = iterator(y);
if (comp) {
if (j == begin())
return pair<iterator, bool>(__insert(x, y, v), true);
else
--j;
if (key_compare(key(j.node), KeyOfValue()(v))) {
return pair<iterator, bool>(__insert(x, y, v), true);
}
return pair<iterator, bool>(j, false);
}
}
真正的插入函数__insert()
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::__insert(base_ptr x_, base_ptr y_, const Value&v) {
link_type x = (link_type) x_;
link_type y = (link_type) y_;
link_type z;
if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
z = create_node(v);
left(y) = z;
if (y == header) {
root() = z;
rightmost() = z;
} else if (y == leftmost()) {
leftmost() = z;
}
} else {
z = create_node(v);
right(y) = z;
if (y == rightmost()) {
rightmost() = z;
}
}
parent(z) = y;
left(z) = 0;
right(z) =0;
__rb_tree_rebalance(z, header->parent);
++node_count;
return iterator(z);
}
调整RB-tree(旋转及改变颜色)
任何插入操作,节点插入完毕后,都要进行一次调整操作,将树的状态调整到符合RB-tree的要求。__rb_tree_rebalance()是具备如此能力的一个全局函数:
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;
if (y && y->color == __rb_tree_red) { // 前文提到的状态3
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) {
x = x->parent;
__rb_tree_rotate_left(x, root);
}
x->parent->color = __rb_tree_black; //改颜色
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;
if (y && y->color == __rb_tree_red ) {
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) {
x = x->parent;
__rb_tree_rotate_right(x, root);
}
x->parent->color = __rb_tree_black;
x->parent->parent->color = __rb_tree_red;
__rb_tree_rotate_left(x->parent->parent, root);
}
}
} // while 结束
root->color = _rb_tree_black;
}
这个属性调整操作,就是前面提到的“由上而下的程序”。从源代码清楚可见,某些时候只需要调整节点颜色,某些时候要做单旋,某些时候要做双旋;某些时候要左旋,某些时候要右旋。下面是左旋和右旋函数
inline void __rb_tree_rotate_left(__rb_tree_node*x, __rb_tree_node_base*&root) {
__rb_tree_node_base* y = x->right;
if (y->left != 0) {
y->left->parent = x
}
y->parent = x->parent;
if (x == root) {
root = y;
} else if (x == x->parent->left) {
x->parent->left = y;
} else {
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) {
__rb_tree_node_base*y = x->left;
x->left = y->right;
if (y->right != 0 ) {
y->right->parent = x;
}
y->parent = x->parent;
if (x == root) {
root = y;
} else if (x == x->parent->right ) {
x->parent->right = y;
} else {
x->parent->left = y;
}
y->right = x;
x->parent = y;
}
元素的搜寻
RB-tree是一个二叉搜索树,元素的搜寻真是其拿手项目。以下是RB-tree提供的find函数
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::find(const Key&k) {
link_type y = header;
link_type x = root();
while(x!=0) {
if (!key_compare(key(x),k)) {
y = x;
x = left(x);
} else {
y = x;
x = right(x);
}
}
iterator j = iterator(j);
return (j == end() || key_compare(k, key(j.node))) ? end() : j;
}
此处有一个疑问,书中通篇没有提及红黑树中元素删除的处理步骤;后续通过其他途径进行补充