您的位置:首页 > 编程语言 > C语言/C++

STL源码阅读(六)

2016-08-05 12:21 330 查看

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记录树的大小
// 上面已经列出了红黑树的性质破坏时,正确维护它们的函数。其它增删改查就很容易实现了。


参考资料

sgi STL

cppreference.com

算法导论 Thomas H.Cormen / Charles E.Leiserson / Ronald L.Rivest / Clifford Stein

CSDN KangRoger的专栏
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ STL SGI RB-tree