STL源码剖析之关联式容器set的底层实现RB-tree
2011-06-12 15:47 Aga.J 阅读(2579) 评论(0) 编辑 收藏 举报57
RB-tree
红黑树:(满足以下条件)1 二叉搜索树
2 每个节点不是红色就是黑色
3 根节点一定为黑色
4 如果节点为红,那么子节点必须为黑(如果节点为黑,子节点可以为黑也可以为红)
(新增加的节点既然一定要为红色,那么其父节点一定要为黑色【根据第5条】)
5 任意一个节点到树尾端的任何路径,所含的黑节点数必须“相等”(暗示着新增加的节点一定只能是红色,可以通过调换其他节点的颜色来做到满足)
总结起来就是说,在插入删除等操作过程中,必须维护这样的树结构:新插入的节点只能是红色,并且只能挂在黑色节点上,如果不能满足这样的情况,就必须旋转树,重新绘制树节点的颜色。
1) 插入节点
这里想要插入3,8,35,75,根据二叉搜索树的插入过程,最终的插入点位置如图所示。但是这种插入形式违反了 【插入点必须为红,红色节点的子节点必须为黑】 的原则。如果插入点的父节点为红,所以其祖先节点必定为黑,所以我们可以确定如图左边的那种树型结构。(保持调整后祖先节点仍然为黑色!!)
下面分6种情况介绍红黑树的插入操作:
1 插入点的父亲为红,父亲的兄弟节点为黑,插入点在外侧
2 插入点的父亲为红,父亲的兄弟节点为黑,插入点在内侧
3 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧
4 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧(父亲的祖父节点为红)
5 插入点的父亲为红,父亲的兄弟节点为红,插入点在内侧(两次旋转)
6 插入点的父亲为黑,直接插入
先进行第一次旋转后变色后得到的结果是根部节点是红的,所以需要再旋转。
58 一个自上而下的程序
59 RB树的节点定义
Typedef bool __rb_tree_color_type;
Const __rb_tree_color_type __rb_tree_red= false;
Const __rb_tree_color_type __rb_tree_black=true;
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){}
};
Template<class value>
Struct __rb_tree_node: public __rb_tree_node_base
{
Typedef __rb_tree_node<Value>* link_type; //link_type类型?
Value value_field; // 节点值
//其他基本的节点信息,如果颜色,左右子树,父亲节点等都已经在基类中定义
};
60
RB-tree的迭代器
要成功将RB-tree实现为一个泛型容器,首先要考虑他的类别,然后考虑他的前进,后退,提取,成员访问等!
SGI将RB-tree迭代器的实现像slist一样分为两层,node继承自node基类,iteraot继承是iterator基类。
基类的节点完成的基本的节点构造,而子类则根据自身所需要,在rb节点的基类上拓展
基类的迭代器 保存迭代器内部指针和迭代器通用操作increase等,而子类则根据自身需要,完成更高层次的封装。
Struct __rb_tree_base_iterator
{
Typedef __rb_tree_node_base::base_ptr base_ptr;
Typedef bidirectional_iterator_tag iterator_categroy;
Typedef ptrdiff_t difference_type;
Base_ptr node; //实际节点指针,和容器产生一个连结关系
Void increment() //在二叉搜索树中找到正确位置
{
If ( node->right != 0 ) //如果有右子节点,查找右子树的最左节点
{
Node = node->right;
While ( node->left !=0)
Node = node -> left;
}
Else //如果没有右子节点
{
Base_ptr y = node -> parent; //找出父亲节点
//如果当前节点在父节点的右子树,那就要上溯,因为父节点的父节点的子树//种存在大于当前节点的节点,直到不为右子节点
While( y->right == node) //一直上溯,直到不为右节点为止
{
Node = y;
Y = y->parent;
}
If( node->right != y)
Node = y; //除了node->right!=y,还有一个隐含条件是node为y的左子节点,所以最后返回y
//这里为了应付,我们想寻找根节点的下一个节点,但是碰巧根节点没有右子节点
}
}
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)
y = y->right ;
node = y ;
}
Else //既非根,也无左节点
{
Base_ptr y = node->parent;
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的节点 __rb_tree_node
__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;}
Pointer operator->() const{return &(operator*());}
Self& operator++() //再做进一步的封装,调用的是基类的通用函数increment。
{
Increment();
Return *this;
}
Self operator++(int)
{
Self tmp = *this;
Increment();
Return tmp;
}
Self& operator—(){}
Self operator—(int){}
};
70
RBtree的数据结构(前面已经介绍了node以及利用node的iterator)
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 __tb_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();}
//隐藏底层的空间分配调用
//分配一个节点,因为rb_tree_node_allocator是用rb_tree_node为基本分配单位
Void put_node(link_type p){rb_tree_node_allocator::deallocate(p);} //释放一个节点
Link_type create_node( const value_type& x) //创建一个值为x的节点
{ //底层的创建节点,并没有涉及到树!
Link_type temp = get_node(); // get_node是为这个函数服务的
__STL_TRY
{
Construct( &tmp->value_field, x); //构造内容,将x赋值在value_field
}
__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;
Link_type& root() const{return (link_type&) header->parent;}
Link_type& leftmode() const{ return (link_type& )header->left;}
Link_type& rightmose() const{ return ( link_type&)header->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 const 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 maxnum( link_type x){}
Public:
Typedef __rb_tree_iterator<value_type, reference, pointer> iterator;
Private:
Iterator __insert(base_ptr x, base_ptr y, const value_type& v);
Link_type __copy ( link_type x , link_type p);
Void __erase( link_type x);
Void init();
//底层的插入,删除,初始化,复制等操作
Public:
Rb_tree ( const Compare& comp= Compare() ) : node_count(0),key_compare(comp)
{ init(); }
~rb_tree() { clear(); put_node(header);}
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:
//供上层调用的插入等接口
Pait<iterator,bool> insert_unique(const value_type& x);
Iterator insert_equal( const value_type& x);
//…
};
Void init()
{
Header=get_node();
Color(header) = __rb_tree_red;
Root()=0;
Lefrmost()=header;
Rightmost()=header;
}
71
红黑树的构造
Rb_tree<int ,int , identity<int>, less<int> > itree; //实例化对象,调用默认构造函数
Rb_tree(const Compare& comp= Compare() )
: node_count(0), key_compare(comp) {init();}
即使红黑树内的节点为空,也保留一个head节点来避免边界问题,这是个不错的思路。
Header帮助我们避免了树形结构操作的边界值问题,它将父节点指向根,左节点指向最小,右节点指向最右。
72
RB-tree的元素操作
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_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); // x是插入的空点,y是该空点的父亲,v是值
//如果x一开始就等于0,那还有header作为边界值的哨兵,可以完成插入__insert操作
}
Template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
Pair<typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator, bool>
Rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
Insert_unique(const Value& v)
{
Link_type y = header;
Link_type x = root();
Bool comp= true;
While(x!=0)
{
Y=x;
Comp = key_compare (KeyOfValue()(v), key(x));
X = comp ? left(x) : right(x);
}
Iterator j = iterator(y); // 迭代器指向插入点的父节点y,这时候它是叶子节点
If(comp) // 如果离开while时comp为真,即 遇到比v大的,所以要插入左侧
If( j==begin()) //如果插入节点的父节点是最左节点
Return pair<iterator,bool>(__insert(x,y,v),true);
Else
--j; //否则往前(左)偏一位(查看前面的是否会出现相等的情况)
If ( key_compare ( key(j.node), KeyOfValue()(v) )) //比较如果小于v,那么就插入右侧
Return pair<iterator,bool>(__insert(x,y,v),true);
Return pair< iterator, bool> (j,false); //相等!
}
真正在RB树结构上完成插入的函数 __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)
//x是新值插入点,y是插入点的父节点,v是新值
{
Link_type x = (link_type) x_;
Link_type y = (link_type) y_;
Link_type z;
If ( y == header || key_compare( KeyOfValue()(v) ,key(y) )) // y等于header时即树为空
//y恰好就是header //y的值大于v
{
Z = create_node(v);
Left(y) = z; //y的左子树指向z
If(y==header) //考虑得十分周到,还有一开始树为空的情况,极端情况
{
Root() = z; //同时,也就是说树一开始为空,初始化时root,right,left都指向z
Rightmost() = z;
}
Else if ( y == leftmost() ) //如果父节点y是最左,那z更左
Leftmost() = z;
}
Else //y的值小于v
{
Z = create_node(v);
Right(y) = z;
If ( y == rightmost() ) //考虑得十分周到,还有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_rebalance()的具体实现
//插入节点后,可能不满足红黑树的特性,所以需要进行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) //父节点为红色,发生了冲突
{
//还考虑了x!=root这个边界情况
If( x->parent == x->parent->parent->left)
//判断父节点是不是为祖先节点的左节点
{
__rb_tree_node_base* y= x->parent->parent->right;
//取得伯父节点,后面根据伯父节点来操作
下面分6种情况介绍红黑树的插入操作:
1 插入点的父亲为红,父亲的兄弟节点为黑,插入点在外侧
2 插入点的父亲为红,父亲的兄弟节点为黑,插入点在内侧
3 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧
4 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧(父亲的祖父节点为红)
5 插入点的父亲为红,父亲的兄弟节点为红,插入点在内侧(两次旋转)
6 插入点的父亲为黑,直接插入
这里判断父节点是否为祖先节点的左节点和 取得伯父节点,判断伯父节点的颜色的目的是为了识别以上者6种情况
if( y && y->color==__rb_tree_red)
//不需要旋转,直接调整颜色,但是要调整到祖父的颜色,所以要再检查祖父的颜色是否达到要求,
{
x->parent->color = __rb_tree_black;
y->color = __rb_tree_black;
x->parent->parent->color= __rb_tree_ted;
x = x->parent->parent; //让祖父节点再被考察一次
}
Else // 没有伯父节点或者伯父节点为黑
{
If ( x == x->parent->right) //如果新节点为父节点的右子节点,也就是在内侧,满足第2种情况
{
X= x->parent;
__rb_tree_rotate_left(x,root); //进行左旋
}
//左旋后到达这个图形,满足第1种情况,然后做下面的处理,做右旋
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;
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);
}
}
}
Root->clolor=_rb_tree_black;
}
红黑树的使用
Rb_tree<int ,int ,identity<int>, less<int> > itree;
73
红黑树的查找
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>::find(const Key& k)
{
Link_type y = header;
//用来保存最后一个不小于k的节点,出现没有不等于的情况时可以根据这个进行处理
Link_type x= root();
While(x!=0)
{
If (!key_compare(key(x),k) ) // 将root的key和k进行比较
Y = x, x=left(x); //如果大于等于,则向左走
Else
X=right(x);
}
Iterator j = iterator(y); //找到等于或者最靠近的大于
Return ( j==end() || key_compare( k, key(j.node)) ? end(): j ;
}
74 Set集合(底层使用红黑树)
集合set的特征: 所有元素都会根据元素的值 自动被排序,而且不像map一样拥有 value和key, set的元素key键值就是实值value。不能有相同的键值。
我们不可以随便的通过set的迭代器来改变set的元素值,因为这样会破坏了set的组织,所以我们的set迭代器是一个constant iterator。
标准的STL中的set底层使用的是RB—tree。
Template<class Key, class Compare= less<Key>, class Alloc = allloc>
Class set
{
Public:
Typedef key key_type;
Typedef key value_type;
Typedef Compare key_compare;
Typedef compare value_compare;
Private:
Typedef tb_tree<key_type, value_type, identity<value_type>,key_compare,alloc> rep_type;
Rep_type t;
Public:
Typedef typename rep_type::const_pointer pointer;
Typedef typename rep_type::const_pointer const_pointer;
Typedef typename rep_type::const_reference reference;
Typedef typename rep_type::const_reference const_reference;
Typedef typename rep_type::const_iterator iterator;
//这里将迭代器定义为const,保证无法写入
Typedef typename rep_type::const_iterator const_iterator;
Typedef typename rep_type::const_reverse_iterator reverse_iterator;
Typedef typename rep_type::const_reverse_iteraotr const_teverse_iterator;
Typedef typename rep_type::size_type size_type;
Typedef typename rep_type::difference_type difference_type;
Set(): t(Compare()){}
Explict set( const Compare& comp): t(comp){}
Template<class InputIteraor>
Set(InputIterator first, InputIterator last)
: t(Compare()) {t.insert_unique(first,last);} //集合内的元素唯一,所以集合不能有重复的key值,或者说叫做value值,因为在set中key就是value
Set(const set<Key,Compare,Alloc>& x): t(x.t){}
Set<Key,Compare,Alloc>& operator=(const set<Key,Compare,Alloc>& x)
{
T = x.t;
Return *this;
}
Key_compare key_comp() const{ return t.key_comp();}
Value_compare value_comp() const {return t.key_comp();}
Iterator begin() const{return t.begin();}
Iterator end() const{return t.end();}
Reverse_iterator rbegin() const {return t.rbegin();}
Bool empty() const{}
Size_type size()
Size_type max_size()
Void swap()
}
作者:Aga.J
出处:http://www.cnblogs.com/aga-j
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
个人学习笔记仅供本人记录知识所用,不属发表性文章。