STL源码阅读(六)

STL源码阅读(六) (SGI STL v3.3)

type_traits.h (<type_traits> C++11)

提供编译时类型信息,C++标准直到C++11才正式支持。SGI type_traits.h提供的编译时类型信息很少,
只提供了_Is_integer判断一个类型是否是整型(bool, char, signed char, unsigned char, wchar_t,
short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long),
以及提供了对是否是POD 类型的判断,是否有普通的(trivial)默认构造函数,拷贝构造函数,赋值构造函数和
析构函数。

stl_function.h (<functional>)

unary_function:用来创建单参数函数对象的基类。
binary_function:用来创建双参数函数对象的基类。
plus,minus,multiplies,divides,modulus,negate:算术运算函数对象。
euqal_to,not_equal_to,greater,less,greater_equal,less_equal:关系运算函数对象。
logical_and,logical_or,logical_not:逻辑运算函数对象。
unary_negate,binary_negate:仿函数,取反器。
not1,not2:生成取反器。
binder1st,binder2nd:仿函数,一元函数绑定器,由一个二元函数和一个参数绑定得到一个一元函数。
bind1st,bind2st:生成一元函数绑定器。
unary_compose,binary_compose:非标准。仿函数,函数组合器。
compose1,compose2:生成函数组合器。
pointer_to_unary_function,pointer_to_binary_function:仿函数,指向一元函数,二元函数的指针。
ptr_fun:返回pointer_to_binary_function和pointer_to_unary_function。
select1st,select2nd:非标准。返回二元组pair的元素。
project1st,project2nd,constant_void_fun,constant_unary_fun,constant_binary_fun,
constant0,constant1,constant2,subtractive_rng:非标准。提供这些函数,并没有多大意义。
mem_fun_t,const_mem_fun_t,mem_fun_ref_t,const_mem_fun_ref_t,
mem_fun1_t,const_mem_fun1_t,mem_fun1_ref_t,const_mem_fun1_ref_t:成员函数指针包装器。
mem_fun,mem_fun_ref,mem_fun1,mem_fun1_ref:生成成员函数指针包装器。

stl_tree.h

红黑树的实现(以下知识摘于算法导论),用来实现关联容器(set, map, multiset, multimap)。

红黑树的性质:
红黑树是一颗二叉搜索树,它在每一个结点上增加了一个存储位来表示结点的颜色,可以是RED或BLACK。通过
对任何一条从根节点到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长处2倍,
因而是近似平衡的。
一颗红黑树是满足下面红黑性质的二叉搜索树:
1. 每个结点要么是红色的,要么是黑色的。
2. 根节点是黑色的。
3. 每个叶节点(NIL)是黑色的(常常使用一个哨兵结点表示叶节点,或省略此哨兵结点)。
4. 如果一个结点是红色的,则它的两个子结点都是黑色的。
5. 对每个结点,从该结点到所有后代叶节点的简单路径上,均包含相同数目的黑色结点。

// 注意stl_tree所实现的红黑树的树的形式的一些小区别:
// (1) 头结点不仅指向树根结点,还指向树的最左边的那个结点,以及树的最右边的那个结点。
// (2) 当要删除的结点有两个孩子时,那么的后继结点重新调整位置链接到被删除结点的位置,而不是将后继结点拷贝到这个位置

// 红黑树颜色约束
typedef bool _Rb_tree_Color_type;
const _Rb_tree_Color_type _S_rb_tree_red = false;
const _Rb_tree_Color_type _S_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 _M_color; 
  _Base_ptr _M_parent;
  _Base_ptr _M_left;
  _Base_ptr _M_right;

  static _Base_ptr _S_minimum(_Base_ptr __x)
  {
    while (__x->_M_left != 0) __x = __x->_M_left;
    return __x;
  }

  static _Base_ptr _S_maximum(_Base_ptr __x)
  {
    while (__x->_M_right != 0) __x = __x->_M_right;
    return __x;
  }
};

template <class _Value>
struct _Rb_tree_node : public _Rb_tree_node_base
{
  typedef _Rb_tree_node<_Value>* _Link_type;
  _Value _M_value_field;
};

// 红黑树迭代器(_Rb_tree_iterator),迭代器类型双向迭代器
_Self& operator++() { _M_increment(); return *this; }
// 红黑树是一棵二叉搜索树,对任何结点x,其左子树的中的关键字最大不超过x.key,
// 其右子树中的关键字最小不低于x.key
void _M_increment() {   // operator++的实现
    // 迭代到比当前结点大的所有结点的中的最小的那个结点
    // 如果右子树存在,那么就是右子树最左边的叶子结点
    if (_M_node->_M_right != 0) {   
      _M_node = _M_node->_M_right;
      while (_M_node->_M_left != 0)
        _M_node = _M_node->_M_left;
    }
    else {  
        // 当前结点不存在右子树时,且当前结点是父结点右结点时。那么,
        // 一直上溯到其不为右节点为止
      _Base_ptr __y = _M_node->_M_parent;
      while (_M_node == __y->_M_right) {    // 一直迭代到_M_node不是__y的右子树为止   
        _M_node = __y;
        __y = __y->_M_parent;
      }
    // 当_M_node本身就是个左结点时,那么其父结点便是++迭代到的下一个结点
    // 当_M_node是树最右边的一条边上结点时,_M_node就是树的根结点
    // 当_M_node不是树最右边的一条边上结点时,_M_node就是上面while迭代到的__y
      if (_M_node->_M_right != __y)
        _M_node = __y;
    }
}

_Self& operator--() { _M_decrement(); return *this; }
void _M_decrement() {
    // 当前树只有两层的情况,且当前结点为叶节点。考虑状况(1)。
    if (_M_node->_M_color == _S_rb_tree_red &&
        _M_node->_M_parent->_M_parent == _M_node)   
      _M_node = _M_node->_M_right;
    else if (_M_node->_M_left != 0) {   // 左子树存在,那么--迭代的下一个结点便是左子树最大的那个结点
      _Base_ptr __y = _M_node->_M_left;
      while (__y->_M_right != 0)
        __y = __y->_M_right;
      _M_node = __y;
    }
    else {
      // 当前结点即非根节点,亦不存在左子树。那么,迭代的下一个结点要么是其父结点(本身是个右节点),
      // 要么是左结点第一个非右节点的父结点
      _Base_ptr __y = _M_node->_M_parent;
      while (_M_node == __y->_M_left) {
        _M_node = __y;
        __y = __y->_M_parent;
      }
      _M_node = __y;
    }
}

// 旋转

//        |                                           |
//        y       <--------rotate_left-----           x
//       / \                                         / \
//      x   c     ---------rotate_right---->        a   y
//     / \                                             / \
//    a   b                                           b   c

// 在结点__x做左旋
inline void _Rb_tree_rotate_left(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root)
{
  _Rb_tree_node_base* __y = __x->_M_right;
  __x->_M_right = __y->_M_left;
  if (__y->_M_left !=0)
    __y->_M_left->_M_parent = __x;
  __y->_M_parent = __x->_M_parent;

  if (__x == __root)
    __root = __y;
  else if (__x == __x->_M_parent->_M_left)
    __x->_M_parent->_M_left = __y;
  else
    __x->_M_parent->_M_right = __y;
  __y->_M_left = __x;
  __x->_M_parent = __y;
}

// 在结点__x做右旋
inline void _Rb_tree_rotate_right(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root)
{
  _Rb_tree_node_base* __y = __x->_M_left;
  __x->_M_left = __y->_M_right;
  if (__y->_M_right != 0)
    __y->_M_right->_M_parent = __x;
  __y->_M_parent = __x->_M_parent;

  if (__x == __root)
    __root = __y;
  else if (__x == __x->_M_parent->_M_right)
    __x->_M_parent->_M_right = __y;
  else
    __x->_M_parent->_M_left = __y;
  __y->_M_right = __x;
  __x->_M_parent = __y;
}

// 插入结点后,红黑树性质的维护
// 分为两种情况,所插入的结点的父结点为左结点的情况,和为右节点的情况。
// 而每种又分为三种情景,见下面代码注释

// __x新插入的结点
inline void _Rb_tree_rebalance(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root)
{
  __x->_M_color = _S_rb_tree_red;
    // 只有插入位置的父结点的颜色为红色时,红黑树的性质才会改变
  while (__x != __root && __x->_M_parent->_M_color == _S_rb_tree_red) {
    // 插入位置的父结点是左结点
    if (__x->_M_parent == __x->_M_parent->_M_parent->_M_left) { 
      _Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_right;
      if (__y && __y->_M_color == _S_rb_tree_red) { // 叔结点颜色是红色时
        __x->_M_parent->_M_color = _S_rb_tree_black; // 将父结点的颜色变为黑色
        __y->_M_color = _S_rb_tree_black; // 将叔结点的颜色变为黑色
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; // 将父结点的父结点的颜色变为红色
        __x = __x->_M_parent->_M_parent;    // 待旋转结点
      }
      else {
        if (__x == __x->_M_parent->_M_right) { //待旋转结点的父结点是红色的,且是右结点时多做一次左旋 
          __x = __x->_M_parent;
          _Rb_tree_rotate_left(__x, __root);
        }
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
        _Rb_tree_rotate_right(__x->_M_parent->_M_parent, __root); // 右旋
      }
    }
    else {  // 插入位置的父结点是右结点时,旋转操作和上面对称
      _Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_left;
      if (__y && __y->_M_color == _S_rb_tree_red) {
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __y->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
        __x = __x->_M_parent->_M_parent;
      }
      else {
        if (__x == __x->_M_parent->_M_left) {
          __x = __x->_M_parent;
          _Rb_tree_rotate_right(__x, __root);
        }
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
        _Rb_tree_rotate_left(__x->_M_parent->_M_parent, __root);
      }
    }
  }
  __root->_M_color = _S_rb_tree_black;
}

// 删除结点,红黑树性质的维护
// __z待删除结点
inline _Rb_tree_node_base* _Rb_tree_rebalance_for_erase(_Rb_tree_node_base* __z,
                             _Rb_tree_node_base*& __root,
                             _Rb_tree_node_base*& __leftmost,
                             _Rb_tree_node_base*& __rightmost) {
  _Rb_tree_node_base* __y = __z;
  _Rb_tree_node_base* __x = 0;
  _Rb_tree_node_base* __x_parent = 0;
  if (__y->_M_left == 0)     // __z has at most one non-null child. y == z.
    __x = __y->_M_right;     // __x might be null.
  else
    if (__y->_M_right == 0)  // __z has exactly one non-null child. y == z.
      __x = __y->_M_left;    // __x is not null.
    else {                   // __z has two non-null children.  Set __y to
      __y = __y->_M_right;   //   __z's successor.  __x might be null.
      while (__y->_M_left != 0)
        __y = __y->_M_left;
      __x = __y->_M_right;
    }
  if (__y != __z) {          // relink y in place of z.  y is z's successor
    __z->_M_left->_M_parent = __y; 
    __y->_M_left = __z->_M_left;
    if (__y != __z->_M_right) {
      __x_parent = __y->_M_parent;
      if (__x) __x->_M_parent = __y->_M_parent;
      __y->_M_parent->_M_left = __x;      // __y must be a child of _M_left
      __y->_M_right = __z->_M_right;
      __z->_M_right->_M_parent = __y;
    }
    else
      __x_parent = __y;  
    if (__root == __z)
      __root = __y;
    else if (__z->_M_parent->_M_left == __z)
      __z->_M_parent->_M_left = __y;
    else 
      __z->_M_parent->_M_right = __y;
    __y->_M_parent = __z->_M_parent;
    __STD::swap(__y->_M_color, __z->_M_color);
    __y = __z;
    // __y now points to node to be actually deleted
  }
  else {                        // __y == __z
    __x_parent = __y->_M_parent;
    if (__x) __x->_M_parent = __y->_M_parent;   
    if (__root == __z)
      __root = __x;
    else 
      if (__z->_M_parent->_M_left == __z)
        __z->_M_parent->_M_left = __x;
      else
        __z->_M_parent->_M_right = __x;
    if (__leftmost == __z) 
      if (__z->_M_right == 0)        // __z->_M_left must be null also
        __leftmost = __z->_M_parent;
    // makes __leftmost == _M_header if __z == __root
      else
        __leftmost = _Rb_tree_node_base::_S_minimum(__x);
    if (__rightmost == __z)  
      if (__z->_M_left == 0)         // __z->_M_right must be null also
        __rightmost = __z->_M_parent;  
    // makes __rightmost == _M_header if __z == __root
      else                      // __x == __z->_M_left
        __rightmost = _Rb_tree_node_base::_S_maximum(__x);
  }
  if (__y->_M_color != _S_rb_tree_red) {    // 
    while (__x != __root && (__x == 0 || __x->_M_color == _S_rb_tree_black))
      if (__x == __x_parent->_M_left) {
        _Rb_tree_node_base* __w = __x_parent->_M_right;
        if (__w->_M_color == _S_rb_tree_red) {
          __w->_M_color = _S_rb_tree_black;
          __x_parent->_M_color = _S_rb_tree_red;
          _Rb_tree_rotate_left(__x_parent, __root);
          __w = __x_parent->_M_right;
        }
        if ((__w->_M_left == 0 || 
             __w->_M_left->_M_color == _S_rb_tree_black) &&
            (__w->_M_right == 0 || 
             __w->_M_right->_M_color == _S_rb_tree_black)) {
          __w->_M_color = _S_rb_tree_red;
          __x = __x_parent;
          __x_parent = __x_parent->_M_parent;
        } else {
          if (__w->_M_right == 0 || 
              __w->_M_right->_M_color == _S_rb_tree_black) {
            if (__w->_M_left) __w->_M_left->_M_color = _S_rb_tree_black;
            __w->_M_color = _S_rb_tree_red;
            _Rb_tree_rotate_right(__w, __root);
            __w = __x_parent->_M_right;
          }
          __w->_M_color = __x_parent->_M_color;
          __x_parent->_M_color = _S_rb_tree_black;
          if (__w->_M_right) __w->_M_right->_M_color = _S_rb_tree_black;
          _Rb_tree_rotate_left(__x_parent, __root);
          break;
        }
      } else {                  // same as above, with _M_right <-> _M_left.
        _Rb_tree_node_base* __w = __x_parent->_M_left;
        if (__w->_M_color == _S_rb_tree_red) {
          __w->_M_color = _S_rb_tree_black;
          __x_parent->_M_color = _S_rb_tree_red;
          _Rb_tree_rotate_right(__x_parent, __root);
          __w = __x_parent->_M_left;
        }
        if ((__w->_M_right == 0 || 
             __w->_M_right->_M_color == _S_rb_tree_black) &&
            (__w->_M_left == 0 || 
             __w->_M_left->_M_color == _S_rb_tree_black)) {
          __w->_M_color = _S_rb_tree_red;
          __x = __x_parent;
          __x_parent = __x_parent->_M_parent;
        } else {
          if (__w->_M_left == 0 || 
              __w->_M_left->_M_color == _S_rb_tree_black) {
            if (__w->_M_right) __w->_M_right->_M_color = _S_rb_tree_black;
            __w->_M_color = _S_rb_tree_red;
            _Rb_tree_rotate_left(__w, __root);
            __w = __x_parent->_M_left;
          }
          __w->_M_color = __x_parent->_M_color;
          __x_parent->_M_color = _S_rb_tree_black;
          if (__w->_M_left) __w->_M_left->_M_color = _S_rb_tree_black;
          _Rb_tree_rotate_right(__x_parent, __root);
          break;
        }
      }
    if (__x) __x->_M_color = _S_rb_tree_black;
  }
  return __y;
}


template <class _Key, class _Value, class _KeyOfValue, class _Compare, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Value) >
class _Rb_tree : protected _Rb_tree_base<_Value, _Alloc>;
// _Rb_tree中维护了一个_M_header指向树的header结点
// 另外维护了_M_node_count记录树的大小
// 上面已经列出了红黑树的性质破坏时,正确维护它们的函数。其它增删改查就很容易实现了。

参考资料

  1. sgi STL
  2. cppreference.com
  3. 算法导论 Thomas H.Cormen / Charles E.Leiserson / Ronald L.Rivest / Clifford Stein
  4. CSDN KangRoger的专栏
posted @ 2016-08-05 12:21  corfox  阅读(173)  评论(0编辑  收藏  举报