STL源码之红黑树
红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组;红黑树是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能;它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
红黑树的性质
- 每个节点非红即黑;
- 根节点是黑的;
- 每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的;
- 如图所示,如果一个节点是红的,那么它的两儿子都是黑的;
- 对于任意节点而言,其到叶子点树NULL指针的每条路径都包含相同数目的黑节点。
_Rb_tree的结构图


_Rb_tree的结点结构
_Rb_tree_node的实现如下,几个实现也很简单,在_Rb_tree_node中定义了结点数据域,在基类_Rb_tree_node_base中分别定义了left、right、parent,另外还有一个表示颜色的标记常量。
另外在_Rb_tree_node_base实现了获取最大值与最小值的方法,根据红黑树的性质,获取最大值只需要在右子树上一直搜索,最小值在左子树上一直搜索。
-
template<typename _Val> -
struct _Rb_tree_node : public _Rb_tree_node_base -
{ -
typedef _Rb_tree_node<_Val>* _Link_type; -
#if __cplusplus < 201103L -
_Val _M_value_field; -
_Val* -
_M_valptr() -
{ return std::__addressof(_M_value_field); } -
const _Val* -
_M_valptr() const -
{ return std::__addressof(_M_value_field); } -
#else -
__gnu_cxx::__aligned_buffer<_Val> _M_storage; -
_Val* -
_M_valptr() -
{ return _M_storage._M_ptr(); } -
const _Val* -
_M_valptr() const -
{ return _M_storage._M_ptr(); } -
#endif -
};
_Rb_tree_node_base的实现如下:
-
enum _Rb_tree_color { _S_red = false, _S_black = true }; -
struct _Rb_tree_node_base -
{ -
typedef _Rb_tree_node_base* _Base_ptr; -
typedef const _Rb_tree_node_base* _Const_Base_ptr; -
_Rb_tree_color _M_color; -
_Base_ptr _M_parent; -
_Base_ptr _M_left; -
_Base_ptr _M_right; -
static _Base_ptr -
_S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT -
{ -
while (__x->_M_left != 0) __x = __x->_M_left; -
return __x; -
} -
static _Const_Base_ptr -
_S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT -
{ -
while (__x->_M_left != 0) __x = __x->_M_left; -
return __x; -
} -
static _Base_ptr -
_S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT -
{ -
while (__x->_M_right != 0) __x = __x->_M_right; -
return __x; -
} -
static _Const_Base_ptr -
_S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT -
{ -
while (__x->_M_right != 0) __x = __x->_M_right; -
return __x; -
} -
};
_Rb_tree的迭代器
_Rb_tree的迭代器首先包含了实现萃取机制的一些typedef,当然实现了一些操作符重载,主要来看下++ 和 -- 的重载。
-
template<typename _Tp> -
struct _Rb_tree_iterator -
{ -
typedef _Tp value_type; -
typedef _Tp& reference; -
typedef _Tp* pointer; -
typedef bidirectional_iterator_tag iterator_category; -
typedef ptrdiff_t difference_type; -
typedef _Rb_tree_iterator<_Tp> _Self; -
typedef _Rb_tree_node_base::_Base_ptr _Base_ptr; -
typedef _Rb_tree_node<_Tp>* _Link_type; -
_Rb_tree_iterator() _GLIBCXX_NOEXCEPT -
: _M_node() { } -
explicit -
_Rb_tree_iterator(_Link_type __x) _GLIBCXX_NOEXCEPT -
: _M_node(__x) { } -
reference -
operator*() const _GLIBCXX_NOEXCEPT -
{ return *static_cast<_Link_type>(_M_node)->_M_valptr(); } -
pointer -
operator->() const _GLIBCXX_NOEXCEPT -
{ return static_cast<_Link_type> (_M_node)->_M_valptr(); } -
_Self& -
operator++() _GLIBCXX_NOEXCEPT -
{ -
_M_node = _Rb_tree_increment(_M_node); -
return *this; -
} -
_Self -
operator++(int) _GLIBCXX_NOEXCEPT -
{ -
_Self __tmp = *this; -
_M_node = _Rb_tree_increment(_M_node); -
return __tmp; -
} -
_Self& -
operator--() _GLIBCXX_NOEXCEPT -
{ -
_M_node = _Rb_tree_decrement(_M_node); -
return *this; -
} -
_Self -
operator--(int) _GLIBCXX_NOEXCEPT -
{ -
_Self __tmp = *this; -
_M_node = _Rb_tree_decrement(_M_node); -
return __tmp; -
} -
bool -
operator==(const _Self& __x) const _GLIBCXX_NOEXCEPT -
{ return _M_node == __x._M_node; } -
bool -
operator!=(const _Self& __x) const _GLIBCXX_NOEXCEPT -
{ return _M_node != __x._M_node; } -
_Base_ptr _M_node; -
};
前++的重载
-
_Self& -
operator++() _GLIBCXX_NOEXCEPT -
{ -
_M_node = _Rb_tree_increment(_M_node); -
return *this; -
}
前++的实现是通过_Rb_tree_increment(libstdc++-v3\src\c++98\tree.cc)来完成,其实现如下:
-
_Rb_tree_node_base* -
_Rb_tree_increment(_Rb_tree_node_base* __x) throw () -
{ -
return local_Rb_tree_increment(__x); -
}
-
static _Rb_tree_node_base* -
local_Rb_tree_increment(_Rb_tree_node_base* __x) throw () -
{ -
/* -
如果当前结点有右子节点,那么右子树的最左结点就是++所需的结点 -
*/ -
if (__x->_M_right != 0) -
{ -
__x = __x->_M_right; -
while (__x->_M_left != 0) -
__x = __x->_M_left; -
} -
else -
{ -
/* -
1. 如果当前结点是左子树结点,那么++的结果就是当前结点的父结点 -
2. 如果当前结点是右子树结点,那么++的结果就是父结点的父结点 -
*/ -
_Rb_tree_node_base* __y = __x->_M_parent; -
while (__x == __y->_M_right) -
{ -
__x = __y; -
__y = __y->_M_parent; -
} -
if (__x->_M_right != __y) -
__x = __y; -
} -
return __x; -
}
前--的重载
-
_Self& -
operator--() _GLIBCXX_NOEXCEPT -
{ -
_M_node = _Rb_tree_decrement(_M_node); -
return *this; -
}
_Rb_tree_decrement的实现:
-
_Rb_tree_node_base* -
_Rb_tree_decrement(_Rb_tree_node_base* __x) throw () -
{ -
return local_Rb_tree_decrement(__x); -
}
-
static _Rb_tree_node_base* -
local_Rb_tree_decrement(_Rb_tree_node_base* __x) throw () -
{ -
/* -
从上面的结构图,我们知道,header是红色,并且parent为root,而root的parent为header -
*/ -
if (__x->_M_color == _S_red -
&& __x->_M_parent->_M_parent == __x) -
__x = __x->_M_right; -
else if (__x->_M_left != 0) -
{/*左子树的最大值*/ -
_Rb_tree_node_base* __y = __x->_M_left; -
while (__y->_M_right != 0) -
__y = __y->_M_right; -
__x = __y; -
} -
else -
{ -
_Rb_tree_node_base* __y = __x->_M_parent; -
while (__x == __y->_M_left) -
{ -
__x = __y; -
__y = __y->_M_parent; -
} -
__x = __y; -
} -
return __x; -
}
_Rb_tree的成员构成
通过上述的类结构图可知,_Rb_tree 的具体实现是在 _Rb_tree_impl中,主要定义了三个成员变量:
- _Key_compare _M_key_compare;
- _Rb_tree_node_base _M_header;
- size_type _M_node_count;
_Rb_tree_impl还负责红黑树的初始化操作与内存管理。
-
template<typename _Key_compare, -
bool _Is_pod_comparator = __is_pod(_Key_compare)> -
struct _Rb_tree_impl : public _Node_allocator -
{ -
_Key_compare _M_key_compare; -
_Rb_tree_node_base _M_header; -
size_type _M_node_count; // Keeps track of size of tree. -
_Rb_tree_impl() -
: _Node_allocator(), _M_key_compare(), _M_header(), -
_M_node_count(0) -
{ _M_initialize(); } -
_Rb_tree_impl(const _Key_compare& __comp, const _Node_allocator& __a) -
: _Node_allocator(__a), _M_key_compare(__comp), _M_header(), -
_M_node_count(0) -
{ _M_initialize(); } -
#if __cplusplus >= 201103L -
_Rb_tree_impl(const _Key_compare& __comp, _Node_allocator&& __a) -
: _Node_allocator(std::move(__a)), _M_key_compare(__comp), -
_M_header(), _M_node_count(0) -
{ _M_initialize(); } -
#endif -
private: -
void -
_M_initialize() -
{ -
this->_M_header._M_color = _S_red; -
this->_M_header._M_parent = 0; -
this->_M_header._M_left = &this->_M_header; -
this->_M_header._M_right = &this->_M_header; -
} -
};
_Rb_tree的内存管理
通过获取_M_impl的构造器来完成节点的创建和销毁,这里和我们之前看到的是一致的,内存分配和构造是分开的,在_M_create_node中,先通过构造器去分配,然后通过construct来构造。
-
_Node_allocator& -
_M_get_Node_allocator() _GLIBCXX_NOEXCEPT -
{ return *static_cast<_Node_allocator*>(&this->_M_impl); } -
const _Node_allocator& -
_M_get_Node_allocator() const _GLIBCXX_NOEXCEPT -
{ return *static_cast<const _Node_allocator*>(&this->_M_impl); } -
allocator_type -
get_allocator() const _GLIBCXX_NOEXCEPT -
{ return allocator_type(_M_get_Node_allocator()); } -
protected: -
_Link_type -
_M_get_node() -
{ return _Alloc_traits::allocate(_M_get_Node_allocator(), 1); } -
void -
_M_put_node(_Link_type __p) _GLIBCXX_NOEXCEPT -
{ _Alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1); } -
#if __cplusplus < 201103L -
_Link_type -
_M_create_node(const value_type& __x) -
{ -
_Link_type __tmp = _M_get_node(); -
__try -
{ get_allocator().construct(__tmp->_M_valptr(), __x); } -
__catch(...) -
{ -
_M_put_node(__tmp); -
__throw_exception_again; -
} -
return __tmp; -
} -
void -
_M_destroy_node(_Link_type __p) -
{ -
get_allocator().destroy(__p->_M_valptr()); -
_M_put_node(__p); -
} -
#else -
template<typename... _Args> -
_Link_type -
_M_create_node(_Args&&... __args) -
{ -
_Link_type __tmp = _M_get_node(); -
__try -
{ -
::new(__tmp) _Rb_tree_node<_Val>; -
_Alloc_traits::construct(_M_get_Node_allocator(), -
__tmp->_M_valptr(), -
std::forward<_Args>(__args)...); -
} -
__catch(...) -
{ -
_M_put_node(__tmp); -
__throw_exception_again; -
} -
return __tmp; -
} -
void -
_M_destroy_node(_Link_type __p) noexcept -
{ -
_Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr()); -
__p->~_Rb_tree_node<_Val>(); -
_M_put_node(__p); -
} -
#endif -
_Link_type -
_M_clone_node(_Const_Link_type __x) -
{ -
_Link_type __tmp = _M_create_node(*__x->_M_valptr()); -
__tmp->_M_color = __x->_M_color; -
__tmp->_M_left = 0; -
__tmp->_M_right = 0; -
return __tmp; -
}
_Rb_tree的元素操作
在看源码之前先看下以下几个接口:
-
_Link_type -
_M_begin() _GLIBCXX_NOEXCEPT -
{ return static_cast<_Link_type>(this->_M_impl._M_header._M_parent); } -
_Const_Link_type -
_M_begin() const _GLIBCXX_NOEXCEPT -
{ -
return static_cast<_Const_Link_type> -
(this->_M_impl._M_header._M_parent); -
} -
_Link_type -
_M_end() _GLIBCXX_NOEXCEPT -
{ return static_cast<_Link_type>(&this->_M_impl._M_header); } -
_Const_Link_type -
_M_end() const _GLIBCXX_NOEXCEPT -
{ return static_cast<_Const_Link_type>(&this->_M_impl._M_header); }
_M_insert_equal的元素插入操作
-
template<typename _Key, typename _Val, typename _KeyOfValue, -
typename _Compare, typename _Alloc> -
#if __cplusplus >= 201103L -
template<typename _Arg> -
#endif -
typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator -
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: -
#if __cplusplus >= 201103L -
_M_insert_equal(_Arg&& __v) -
#else -
_M_insert_equal(const _Val& __v) -
#endif -
{ -
pair<_Base_ptr, _Base_ptr> __res -
= _M_get_insert_equal_pos(_KeyOfValue()(__v)); -
return _M_insert_(__res.first, __res.second, _GLIBCXX_FORWARD(_Arg, __v)); -
}
上述代码中调用了_M_get_insert_equal_pos,其中的实现是从根节点开始,往下寻找适当的插入点:
-
template<typename _Key, typename _Val, typename _KeyOfValue, -
typename _Compare, typename _Alloc> -
pair<typename _Rb_tree<_Key, _Val, _KeyOfValue, -
_Compare, _Alloc>::_Base_ptr, -
typename _Rb_tree<_Key, _Val, _KeyOfValue, -
_Compare, _Alloc>::_Base_ptr> -
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: -
_M_get_insert_equal_pos(const key_type& __k) -
{ -
typedef pair<_Base_ptr, _Base_ptr> _Res; -
_Link_type __x = _M_begin(); -
_Link_type __y = _M_end(); -
while (__x != 0)//寻找合适的插入点 -
{ -
__y = __x; -
__x = _M_impl._M_key_compare(__k, _S_key(__x)) ? -
_S_left(__x) : _S_right(__x);//遇大往左,遇小往右 -
} -
return _Res(__x, __y);//x为插入点,y为插入点的父结点 -
}
_M_insert_unique的元素插入操作
-
template<typename _Key, typename _Val, typename _KeyOfValue, -
typename _Compare, typename _Alloc> -
#if __cplusplus >= 201103L -
template<typename _Arg> -
#endif -
pair<typename _Rb_tree<_Key, _Val, _KeyOfValue, -
_Compare, _Alloc>::iterator, bool> -
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: -
#if __cplusplus >= 201103L -
_M_insert_unique(_Arg&& __v) -
#else -
_M_insert_unique(const _Val& __v) -
#endif -
{ -
typedef pair<iterator, bool> _Res; -
pair<_Base_ptr, _Base_ptr> __res -
= _M_get_insert_unique_pos(_KeyOfValue()(__v)); -
if (__res.second) -
return _Res(_M_insert_(__res.first, __res.second, -
_GLIBCXX_FORWARD(_Arg, __v)), -
true); -
return _Res(iterator(static_cast<_Link_type>(__res.first)), false); -
}
看下_M_get_insert_unique_pos的主要实现:
1. 插入新值,不允许重复,若重复插入无效
2. 返回值是个pair:第一个元素是rb-tree迭代器指向新增结点;第二个表示成功与否
-
template<typename _Key, typename _Val, typename _KeyOfValue, -
typename _Compare, typename _Alloc> -
pair<typename _Rb_tree<_Key, _Val, _KeyOfValue, -
_Compare, _Alloc>::_Base_ptr, -
typename _Rb_tree<_Key, _Val, _KeyOfValue, -
_Compare, _Alloc>::_Base_ptr> -
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: -
_M_get_insert_unique_pos(const key_type& __k) -
{ -
typedef pair<_Base_ptr, _Base_ptr> _Res; -
_Link_type __x = _M_begin(); -
_Link_type __y = _M_end(); -
bool __comp = true; -
while (__x != 0)//从根节点开始,寻找合适的插入点 -
{ -
__y = __x; -
__comp = _M_impl._M_key_compare(__k, _S_key(__x)); -
__x = __comp ? _S_left(__x) : _S_right(__x); -
} -
iterator __j = iterator(__y);//指向插入点的父结点 -
if (__comp)//comp为true,说明插在左侧 -
{ -
if (__j == begin())//插入结点的父结点为最左侧结点 -
return _Res(__x, __y); -
else -
--__j; -
} -
//新键值不与既有结点重复,于是执行安插 -
if (_M_impl._M_key_compare(_S_key(__j._M_node), __k)) -
return _Res(__x, __y); -
return _Res(__j._M_node, 0); -
}
_M_insert_的插入操作
__x,__p,__v分别为插入点,插入点父结点,以及新值。
-
template<typename _Key, typename _Val, typename _KeyOfValue, -
typename _Compare, typename _Alloc> -
#if __cplusplus >= 201103L -
template<typename _Arg> -
#endif -
typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator -
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: -
#if __cplusplus >= 201103L -
_M_insert_(_Base_ptr __x, _Base_ptr __p, _Arg&& __v) -
#else -
_M_insert_(_Base_ptr __x, _Base_ptr __p, const _Val& __v) -
#endif -
{ -
bool __insert_left = (__x != 0 || __p == _M_end() -
|| _M_impl._M_key_compare(_KeyOfValue()(__v), -
_S_key(__p))); -
_Link_type __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v)); -
_Rb_tree_insert_and_rebalance(__insert_left, __z, __p, -
this->_M_impl._M_header); -
++_M_impl._M_node_count; -
return iterator(__z); -
}
_Rb_tree_insert_and_rebalance这个函数才是实现的重点,在这里会更新插入结点之后的leftmost、rightmost的更新;以及如果不满足红黑树的性质,就进行调整。
在这里需要结合:数据结构与算法——红黑树(Red Black Tree)中的几种插入情况。
-
void -
_Rb_tree_insert_and_rebalance(const bool __insert_left, -
_Rb_tree_node_base* __x, -
_Rb_tree_node_base* __p, -
_Rb_tree_node_base& __header) throw () -
{ -
_Rb_tree_node_base *& __root = __header._M_parent; -
// Initialize fields in new node to insert. -
__x->_M_parent = __p; -
__x->_M_left = 0; -
__x->_M_right = 0; -
__x->_M_color = _S_red; -
// Insert. -
// Make new node child of parent and maintain root, leftmost and -
// rightmost nodes. -
// N.B. First node is always inserted left. -
if (__insert_left) -
{ -
__p->_M_left = __x; // also makes leftmost = __x when __p == &__header -
if (__p == &__header) -
{ -
__header._M_parent = __x; -
__header._M_right = __x; -
} -
else if (__p == __header._M_left) -
__header._M_left = __x; // maintain leftmost pointing to min node -
} -
else -
{ -
__p->_M_right = __x; -
if (__p == __header._M_right) -
__header._M_right = __x; // maintain rightmost pointing to max node -
} -
// Rebalance. -
while (__x != __root -
&& __x->_M_parent->_M_color == _S_red) //父结点为红 -
{ -
_Rb_tree_node_base* const __xpp = __x->_M_parent->_M_parent;//获取祖父结点 -
if (__x->_M_parent == __xpp->_M_left) //父结点为祖父结点的左子结点 -
{ -
_Rb_tree_node_base* const __y = __xpp->_M_right; -
if (__y && __y->_M_color == _S_red) //对应状况1 -
{ -
__x->_M_parent->_M_color = _S_black; -
__y->_M_color = _S_black; -
__xpp->_M_color = _S_red; -
__x = __xpp; -
} -
else -
{//无伯父结点 -
if (__x == __x->_M_parent->_M_right) //新结点为父结点的右子结点,对应状况2 -
{ -
__x = __x->_M_parent; -
local_Rb_tree_rotate_left(__x, __root); -
} -
__x->_M_parent->_M_color = _S_black;//经过左旋之后,对应状况3,需要再做一次右旋 -
__xpp->_M_color = _S_red; -
local_Rb_tree_rotate_right(__xpp, __root); -
} -
} -
else -
{ -
_Rb_tree_node_base* const __y = __xpp->_M_left; -
if (__y && __y->_M_color == _S_red) //类似于状况1,只不过为祖父结点的右子结点 -
{ -
__x->_M_parent->_M_color = _S_black; -
__y->_M_color = _S_black; -
__xpp->_M_color = _S_red; -
__x = __xpp; -
} -
else -
{ -
if (__x == __x->_M_parent->_M_left) //类似于2,3,只不过是做相反的旋转 -
{ -
__x = __x->_M_parent; -
local_Rb_tree_rotate_right(__x, __root); -
} -
__x->_M_parent->_M_color = _S_black; -
__xpp->_M_color = _S_red; -
local_Rb_tree_rotate_left(__xpp, __root); -
} -
} -
} -
__root->_M_color = _S_black; -
}
状况1:
此时将当前结点的父结点和叔叔节点涂黑,祖父结点涂红;并把当前结点指向祖父结点,从新的当前结点重新开始计算。

状况2:
当前结点的父结点作为新的当前结点,以新当前结点为支点进行左旋。

状况3:
此时将父结点变为黑色,祖父结点变为红色,祖父结点作为支点进行右旋。

右旋的实现local_Rb_tree_rotate_right:
-
static void -
local_Rb_tree_rotate_right(_Rb_tree_node_base* const __x, -
_Rb_tree_node_base*& __root) -
{ -
_Rb_tree_node_base* const __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; -
}

左旋的实现local_Rb_tree_rotate_left:
-
static void -
local_Rb_tree_rotate_left(_Rb_tree_node_base* const __x, -
_Rb_tree_node_base*& __root) -
{ -
_Rb_tree_node_base* const __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; -
}

以上参考:
- STL源码剖析
- https://www.cnblogs.com/newobjectcc/p/11293689.html
- 【B站最全面的红黑树结构详解】数据结构红黑树,二叉树,HASH,B+树详解,平衡算法详解_哔哩哔哩_bilibili
(1742条消息) C++进阶——STL源码之红黑树(_Rb_tree)__m_get_insert_unique_pos_&动感超人的博客-CSDN博客

503

被折叠的 条评论
为什么被折叠?



