代码改变世界

STL源码剖析之关联式容器set的底层实现RB-tree

2011-06-12 15:47  Aga.J  阅读(2579)  评论(0编辑  收藏  举报

57

RB-tree

红黑树:(满足以下条件) 

1 二叉搜索树

2 每个节点不是红色就是黑色

3 根节点一定为黑色

4 如果节点为红,那么子节点必须为黑(如果节点为黑,子节点可以为黑也可以为红)

新增加的节点既然一定要为红色,那么其父节点一定要为黑色【根据第5条】)

5 任意一个节点到树尾端的任何路径,所含的黑节点数必须“相等”(暗示着新增加的节点一定只能是红色,可以通过调换其他节点的颜色来做到满足)

  总结起来就是说,在插入删除等操作过程中,必须维护这样的树结构:新插入的节点只能是红色,并且只能挂在黑色节点上,如果不能满足这样的情况,就必须旋转树,重新绘制树节点的颜色。

 

1) 插入节点

 clip_image002

  这里想要插入3,8,35,75,根据二叉搜索树的插入过程,最终的插入点位置如图所示。但是这种插入形式违反了 【插入点必须为红,红色节点的子节点必须为黑】 的原则。如果插入点的父节点为红,所以其祖先节点必定为黑,所以我们可以确定如图左边的那种树型结构。(保持调整后祖先节点仍然为黑色!!)

下面分6种情况介绍红黑树的插入操作:

  1 插入点的父亲为红父亲的兄弟节点为黑,插入点在外侧

  2 插入点的父亲为红,父亲的兄弟节点为黑,插入点在内侧

 

  3 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧

  4 插入点的父亲为红,父亲的兄弟节点为红,插入点在外侧(父亲的祖父节点为红

  5 插入点的父亲为红,父亲的兄弟节点为红,插入点在内侧(两次旋转)

 

  6 插入点的父亲为黑,直接插入

 clip_image004

 clip_image006

先进行第一次旋转后变色后得到的结果是根部节点是红的,所以需要再旋转。

 clip_image008

 clip_image010

 

58 一个自上而下的程序

 clip_image012

 clip_image014

 clip_image016

 

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基类。

 clip_image018

基类的节点完成的基本的节点构造,而子类则根据自身所需要,在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);}

 clip_image020

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();}

 clip_image022

clip_image024

即使红黑树内的节点为空,也保留一个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)

//不需要旋转,直接调整颜色,但是要调整到祖父的颜色,所以要再检查祖父的颜色是否达到要求,

  {

clip_image026

    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种情况

    {

clip_image028

      X= x->parent;

      __rb_tree_rotate_left(x,root); //进行左旋

   }

clip_image030//左旋后到达这个图形,满足第1种情况,然后做下面的处理,做右旋

x->parent->color = __rb_tree_black;

x->parent->parent->color = __rb_tree_red;

__rb_tree_rotate_right(x->parent->parent,root);

clip_image032  //最后形成这样

}

}

Else      //父节点是右子节点

{

__rb_tree_node_base* y = x->parent->parent->left;

If( y&& y->color == rb_tree_red)

{

clip_image034

//简单修改颜色就可以

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) //先判断是否要进行叶子上的旋转

{

clip_image036

X = x->parent;

__rb_tree_rotate_right (x,root);

}

clip_image038

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()

clip_image040

}