RB-tree的节点设计
RB-tree有红黑二色,并且拥有左右子节点,我们很容易就可以勾勒出其结构风貌。以下是SGI STL的实现代码。为了有更大的弹性,节点分为两层:从以下的minimum()和maximum()函数可清楚看出,RB-tree作为一个二叉搜索树,其极致是多么容易找到。由于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;//RB树的许多操作,必须知道父节点
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的节点图标,其中将 _rb_tree_node:value_field填为10:
RB-tree的迭代器
要成功将RB-tree实现一个泛型容器,迭代器的设计是一个关键。首先我们要考虑它的类别(category),然后要考虑它的前进(increment)、后退(decrement)、提领(dereference)、成员访问(member access)等操作。
为了更大的弹性,SGI将RB-tree迭代器实现为两层,这种设计理念和slist类似。下图所示便是双层节点和双层迭代器结构之间的关系。其中主要意义是:_rb_tree_node继承自 _rb_tree_node_base, _rb_tree_iterator继承自 _rb_tree_base_itertor。有啦这样的认知,我们就可以将迭代器稍作转型,然后解开RB-tree的所有奥秘,追踪其一切状态:
RB-tree迭代器属于双向迭代器,但不具备随机定位能力,其提领操作和成员访问操作与list十分相似,较为特殊的是其前进和后退操作。注意。RB-tree迭代器的前进操作operator++()调用了基层迭代器的increment(),RB-tree迭代器的后退操作operator–()则调用了基层迭代器的decrement()、前进或者后退的举止行为完全依据二叉搜索树的节点排列法则,再加上实现上的某些特殊技巧。
struct _rb_tree_base_iterator
{
typedef _rb_tree_node_base::base_ptr base_ptr;
tyopedf bidirectional_iterator_tag iterator_category;
typedef ptrdiff_t difference_type;
base_ptr node;//用来与容器之间产生一个连结关系(make a reference)
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为解答
}
//以上判断“若此时的右子节点不等于此时的父节点”,是为了应付一种特殊情况:我们欲寻找根节点的下一节点,而恰好根节点无右子节点。当然,以上特护做法必须配合RB-tree根节点与特殊之header之间的特殊关系。
void decrement()
{
if(node->color==_rb_tree_red &&node->parent->parent==node)//如果是红节点,且父节点的父亲点等于自己
node=node->right;
else if(node->left!=0)
{
base_ptr y=node->left;
while(y->right!=0)
u=y->right;
node=y;
}
else {
base_ptr y=node->left;
while(node==y->left)
node=y;
y=y->parent;
}
node=y;
}
};
//RB-tree的正规迭代器
template<class Value,class Ref,class Ptr>
struct _rb_tree_iterator:public _rb_tree_base_iterator
{
typedef Value value_type;
typedef Ref reference;
typedef Ptr pointer;
typedef _rb_tree_iterator<Value,Value&,Value*> iterator;
typedef _rb_tree_iterator<Value, const Value&, const Value*> const_iterator;
typedef _rb_tree_iterator<Value,Ref, Ptr> self;
typedef _rb_tree_node<Value>*link_type;
_rb_tree_iterator(){}
_rb_tree_iterator(link_type x){node=x;}
_rb_tree_iterator(const iterator& it){node=it.node;}
reference operator*() const{return link_type(node)->value_field;}
#ifdef _SGI_STL_NO_ARROW_OPERATOR
pointer operator->()const{return &(operator*());}
#denif
self& operator++() {increment();return *this;}
self operator++(int)
{self tmp=*this;
increment();
return tmp;
}
self& operator--(){decrement(); return *this;}
self operator--(int)
{self tmp=*this;
decrement();
return tmp;
}
};