STL提供了许多好用的数据结构与算法,使我们不必为做许许多多的重复劳动。STL里实现了一个树结构-Red-Black Tree,它也是STL里唯一实现的一个树状数据结构,并且它是map, multimap,set,multiset的底层实现,如果学会了Red-Black Tree,那么对我们高效的运用STL是很有帮助的。
1. 什么是红黑树
红黑树是二叉查找树的一种,由于它能够保证树的高度比较底,所以是一种性能较好的查找树。它需要满足以下几条性质:
1.每个结点或是红的,或是黑的
2.根结点是黑的
3.如果一个结点是红的,那么它两个儿子都是黑的
4.对于每个结点,从该结点到其子孙结点的所有路径上包含数目相同的黑结点
2. 红黑树的操作
红黑树的操作与大多数二叉树操作相同,主要有增加新结点,删除结点,查找结点等等。但是它并不支持直接修改结点,因为结点被修改后会破坏结构,所以在STL中我们也不对一个迭代器的key进行修改。
对于删除与添加操作,因为可能会破坏平衡树的性质,所以我们需要重新对结构进行调整,以使整个树结构保持上述五个性质。由于插入与添加操作涉及比较复杂,我们等到正式讲解STL里实现的时候再详细说明。
因为红黑树可以保证对于N个结点的树,树深度不超过log(2N),所以效率还是相同高的哦。
3. 红黑树结点的定义
下面代码定义了红黑树的结点:
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;
};
由上面的定义可以看出来,每个结点维护了三个指针:父结点_M_parent,左子结点_M_left,右子结点_M_right,同时还有一个颜色标记_M_color,再就是结点的值_M_value_field。同时可以求得当以某个结点为根的最小与最大结点。因为最小结点一定是最左的子孙结点,最大一定是最右的子孙结点。
4. 红黑树的迭代器定义
迭代器是STL里面非常重要的一部分,这里就不细说了,要说的话几天也说不完。RB Tree里提供的迭代哭是双向迭代器bidirectional_iterator_tag,即可以向前走一步,也可以向后走一步,但是不能像操作指针一样,一下子就走好几步。但考虑到它是树结构,所以它所谓的走向前一个或后一个结点也不是那么简单。还好,STL迭代器里定义了两个函数做到这一步。这其实有点像树的中序遍历,把树的结点排起来,前一个结点就是中序的前一个结点(比它小但是最大的结点),后一个结点就是中序的后一个结点(比它大但是最小的结点)。
{
typedef _Rb_tree_node_base::_Base_ptr _Base_ptr;
typedef bidirectional_iterator_tag iterator_category;
typedef ptrdiff_t difference_type;
_Base_ptr _M_node;
void _M_increment() //求下一个结点
{
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;
__y = __y->_M_parent;
}
if (_M_node->_M_right != __y) //前面不用判断根结点,这里再回退,因为
_M_node = __y; //实现上增加了一个header结点
}
void _M_decrement() //求上一个结点
{
if (_M_node->_M_color == _S_rb_tree_red &&
_M_node->_M_parent->_M_parent == _M_node)
_M_node = _M_node->_M_right; //header(end())结点的上一个,即为最右子结点
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;
}
}
};
现在还是看起来有点迷糊,后面分析到红黑树以及header结点的作用时才会有一种恍然大悟的感觉。来看看iterator结口提供了哪些功能。
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_iterator() {}
_Rb_tree_iterator(_Link_type __x) { _M_node = __x; }
_Rb_tree_iterator(const iterator& __it) { _M_node = __it._M_node; }
reference operator*() const { return _Link_type(_M_node)->_M_value_field; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
_Self& operator++() { _M_increment(); return *this; }
_Self operator++(int) {
_Self __tmp = *this;
_M_increment();
return __tmp;
}
_Self& operator--() { _M_decrement(); return *this; }
_Self operator--(int) {
_Self __tmp = *this;
_M_decrement();
return __tmp;
}
};
inline bool operator==(const _Rb_tree_base_iterator& __x,
const _Rb_tree_base_iterator& __y) {
return __x._M_node == __y._M_node;
}
inline bool operator!=(const _Rb_tree_base_iterator& __x,
const _Rb_tree_base_iterator& __y) {
return __x._M_node != __y._M_node;
}
可以看到,迭代器的比较是基于指针的比较,并且重载了前置和后置的++,--运算符。它调用的就是_M_decrement()和_M_increment()函数。
5. 红黑树的空间配置器
因为红黑树是动态增长的,所以每次增加或删除结点时都要进行配置,它有一个专用的空间配置器,用来每次申请一个结点的内存或归还一个结点的内存。
class _Rb_tree_alloc_base {
public:
typedef typename _Alloc_traits<_Tp, _Alloc>::allocator_type allocator_type;
allocator_type get_allocator() const { return _M_node_allocator; }
_Rb_tree_alloc_base(const allocator_type& __a)
: _M_node_allocator(__a), _M_header(0) {}
protected:
typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::allocator_type
_M_node_allocator;
_Rb_tree_node<_Tp>* _M_header;
_Rb_tree_node<_Tp>* _M_get_node()
{ return _M_node_allocator.allocate(1); }
void _M_put_node(_Rb_tree_node<_Tp>* __p)
{ _M_node_allocator.deallocate(__p, 1); }
};
// Specialization for instanceless allocators.
template <class _Tp, class _Alloc>
class _Rb_tree_alloc_base<_Tp, _Alloc, true> {
public:
typedef typename _Alloc_traits<_Tp, _Alloc>::allocator_type allocator_type;
allocator_type get_allocator() const { return allocator_type(); }
_Rb_tree_alloc_base(const allocator_type&) : _M_header(0) {}
protected:
_Rb_tree_node<_Tp>* _M_header;
typedef typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::_Alloc_type
_Alloc_type;
_Rb_tree_node<_Tp>* _M_get_node()
{ return _Alloc_type::allocate(1); }
void _M_put_node(_Rb_tree_node<_Tp>* __p)
{ _Alloc_type::deallocate(__p, 1); }
};
总体来看也没什么特别有用的信息,_M_get_node()就是申请一个结点的空间,_M_put_node()就是归还了。它调用了allocater()和deallocate(),这是STL里面的内存分配的类。讲这个也可以讲一天。有兴趣的可以看Stl_alloc.h和Stl_construct.h这两个头文件。
6. RB-Tree代码分析
前面讲了这么多废话,终于进行正题了。期待己久的header结点终于出现了。
struct _Rb_tree_base
{
typedef _Alloc allocator_type;
allocator_type get_allocator() const { return allocator_type(); }
_Rb_tree_base(const allocator_type&)
: _M_header(0) { _M_header = _M_get_node(); }
~_Rb_tree_base() { _M_put_node(_M_header); }
protected:
_Rb_tree_node<_Tp>* _M_header; //这个就是头结点,它刚开始就被分配出来
typedef simple_alloc<_Rb_tree_node<_Tp>, _Alloc> _Alloc_type;
_Rb_tree_node<_Tp>* _M_get_node()
{ return _Alloc_type::allocate(1); }
void _M_put_node(_Rb_tree_node<_Tp>* __p)
{ _Alloc_type::deallocate(__p, 1); }
};
class _Alloc = __STL_DEFAULT_ALLOCATOR(_Value) >
class _Rb_tree : protected _Rb_tree_base<_Value, _Alloc> {
typedef _Rb_tree_base<_Value, _Alloc> _Base;
protected:
typedef _Rb_tree_node_base* _Base_ptr; //结点指针
typedef _Rb_tree_Color_type _Color_type; //结点颜色
public:
typedef _Key key_type; //key类型
typedef _Value value_type; //value类型
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;
typedef typename _Base::allocator_type allocator_type;
allocator_type get_allocator() const { return _Base::get_allocator(); }
protected:
#ifdef __STL_USE_NAMESPACES
using _Base::_M_get_node; //基类定义的东西
using _Base::_M_put_node;
using _Base::_M_header; //header结点,实现上使用的
#endif /* __STL_USE_NAMESPACES */
protected:
_Link_type _M_create_node(const value_type& __x) //根据值建一个结点
{
_Link_type __tmp = _M_get_node();
__STL_TRY {
construct(&__tmp->_M_value_field, __x);
}
__STL_UNWIND(_M_put_node(__tmp));
return __tmp;
}
_Link_type _M_clone_node(_Link_type __x) //复制一个结点,只复制值与颜色
{
_Link_type __tmp = _M_create_node(__x->_M_value_field);
__tmp->_M_color = __x->_M_color;
__tmp->_M_left = 0;
__tmp->_M_right = 0;
return __tmp;
}
void destroy_node(_Link_type __p) //销毁一个结点
{
destroy(&__p->_M_value_field);
_M_put_node(__p);
}
protected:
size_type _M_node_count; // keeps track of size of tree //树结点大小
_Compare _M_key_compare; //比较器,用于比较两个结点的大小
_Link_type& _M_root() const //根结点,header结点的parent是指向根结点的
{ return (_Link_type&) _M_header->_M_parent; }
_Link_type& _M_leftmost() const //最左子结点,header的左儿子指向最左子结点
{ return (_Link_type&) _M_header->_M_left; }
_Link_type& _M_rightmost() const //最右子结点,header的右儿子指向最右子结点
{ return (_Link_type&) _M_header->_M_right; }
static _Link_type& _S_left(_Link_type __x) //求结点相关信息,看函数名容易知道意思
{ return (_Link_type&)(__x->_M_left); }
static _Link_type& _S_right(_Link_type __x)
{ return (_Link_type&)(__x->_M_right); }
static _Link_type& _S_parent(_Link_type __x)
{ return (_Link_type&)(__x->_M_parent); }
static reference _S_value(_Link_type __x)
{ return __x->_M_value_field; }
static const _Key& _S_key(_Link_type __x)
{ return _KeyOfValue()(_S_value(__x)); }
static _Color_type& _S_color(_Link_type __x)
{ return (_Color_type&)(__x->_M_color); }
static _Link_type& _S_left(_Base_ptr __x)
{ return (_Link_type&)(__x->_M_left); }
static _Link_type& _S_right(_Base_ptr __x)
{ return (_Link_type&)(__x->_M_right); }
static _Link_type& _S_parent(_Base_ptr __x)
{ return (_Link_type&)(__x->_M_parent); }
static reference _S_value(_Base_ptr __x)
{ return ((_Link_type)__x)->_M_value_field; }
static const _Key& _S_key(_Base_ptr __x)
{ return _KeyOfValue()(_S_value(_Link_type(__x)));}
static _Color_type& _S_color(_Base_ptr __x)
{ return (_Color_type&)(_Link_type(__x)->_M_color); }
static _Link_type _S_minimum(_Link_type __x) //求最小子结点
{ return (_Link_type) _Rb_tree_node_base::_S_minimum(__x); }
static _Link_type _S_maximum(_Link_type __x) //求最大子结点
{ return (_Link_type) _Rb_tree_node_base::_S_maximum(__x); }
public:
typedef _Rb_tree_iterator<value_type, reference, pointer> iterator; //迭代器类型定义
typedef _Rb_tree_iterator<value_type, const_reference, const_pointer> const_iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_bidirectional_iterator<iterator, value_type, reference,
typedef reverse_bidirectional_iterator<const_iterator, value_type,
const_reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
一直到这里,还没有什么比较难理解的地方,不过我们现在知道了,实现上需要的header结点是这样一个结点,它的父结点是根,它的左右子结点分别指向树中的最左和最右子结点,也就是最小和最大的子结点。
再来看看它的构造函数与析构函数的定义:
// allocation/deallocation
_Rb_tree()
: _Base(allocator_type()), _M_node_count(0), _M_key_compare()
{ _M_empty_initialize(); }
_Rb_tree(const _Compare& __comp)
: _Base(allocator_type()), _M_node_count(0), _M_key_compare(__comp)
{ _M_empty_initialize(); }
_Rb_tree(const _Compare& __comp, const allocator_type& __a)
: _Base(__a), _M_node_count(0), _M_key_compare(__comp)
{ _M_empty_initialize(); }
_Rb_tree(const _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>& __x)
: _Base(__x.get_allocator()),
_M_node_count(0), _M_key_compare(__x._M_key_compare) //拷贝构造函数
{
if (__x._M_root() == 0)
_M_empty_initialize();
else {
_S_color(_M_header) = _S_rb_tree_red;
_M_root() = _M_copy(__x._M_root(), _M_header);
_M_leftmost() = _S_minimum(_M_root());
_M_rightmost() = _S_maximum(_M_root());
}
_M_node_count = __x._M_node_count;
}
~_Rb_tree() { clear(); }
private:
void _M_empty_initialize() {
_S_color(_M_header) = _S_rb_tree_red; // used to distinguish header from
// __root, in iterator.operator++
_M_root() = 0;
_M_leftmost() = _M_header;
_M_rightmost() = _M_header;
}
除了拷贝构造函数外,其余构造函数都是直接将header的父指针指向NULL,左右子结点指向自己。拷贝构造函数调用了_M_copy(),它的作用类似于将__x._M_root()为根的树结点复制到_M_header()为根的树结构中。它是通过_M_clone()来完成的。这样就得到了参数一样的树了。析构函数回收所有申请的内存,这里不再讲述。
iterator begin() { return _M_leftmost(); } //以下几个函数加上前面定义,可知header
const_iterator begin() const { return _M_leftmost(); } //得到相关迭代器
iterator end() { return _M_header; }
const_iterator end() const { return _M_header; }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
bool empty() const { return _M_node_count == 0; } //树是否非空
size_type size() const { return _M_node_count; } //树大小
size_type max_size() const { return size_type(-1); }
void swap(_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>& __t) { //交换
__STD::swap(_M_header, __t._M_header);
__STD::swap(_M_node_count, __t._M_node_count);
__STD::swap(_M_key_compare, __t._M_key_compare);
}
看上面的代码可以知道,header结点就是end()结点,它的左子结点是begin(),从begin()刚好把树遍历一次。树为空时,begin()与end()都指向header,这样就不用对树为空作特殊判断了。可能比较困惑的地方就是rebegin()了,看看它返回的是_M_header,即我们添加的那个header结点,不是它的右儿子么?即最大的那个结点,同理rend()是指向的第一个结点,我们知道一般写代码是这样:
for(auto itr = mapTree.rbegin(); itr != mapTree.rend(); ++itr)
看上去好像是有问题,但是如果熟悉迭代器的就能知道,其实反向迭代器在取值是取它下一个结点的值。即正向迭代中上一个结点的值。所以在rend()上一个结点时,它的值己经被遍历到了。
下面代码开始涉及红黑树的操作了,查找树的三大操作就是:查找,添加,删除。查找操作是最简单的,因为它不涉及树结构的改变。所以我们先来看查找操作的代码:
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 = _M_header; // Last node which is not less than __k.
_Link_type __x = _M_root(); // Current node.
while (__x != 0) //树不为空,查找结点
if (!_M_key_compare(_S_key(__x), __k)) //x结点大于或等于k时就向左走
__y = __x, __x = _S_left(__x); //因为x与k可能相同,故先记录下来当前的x
else
__x = _S_right(__x); //x结点小于k时向右走
iterator __j = iterator(__y); //如果一直向右走,则__j==end(),因为__y不变
return (__j == end() || _M_key_compare(__k, _S_key(__j._M_node))) ? //向左走过的话比较一下
end() : __j;
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::const_iterator
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::find(const _Key& __k) const
{
_Link_type __y = _M_header; /* Last node which is not less than __k. */
_Link_type __x = _M_root(); /* Current node. */
while (__x != 0) {
if (!_M_key_compare(_S_key(__x), __k))
__y = __x, __x = _S_left(__x);
else
__x = _S_right(__x);
}
const_iterator __j = const_iterator(__y);
return (__j == end() || _M_key_compare(__k, _S_key(__j._M_node))) ?
end() : __j;
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::size_type
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::count(const _Key& __k) const //有多个少key为__k的结点
{
pair<const_iterator, const_iterator> __p = equal_range(__k);
size_type __n = 0;
distance(__p.first, __p.second, __n);
return __n;
}
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>
::lower_bound(const _Key& __k) //查找第一个不小于或等于key的结点
{
_Link_type __y = _M_header; /* Last node which is not less than __k. */
_Link_type __x = _M_root(); /* Current node. */
while (__x != 0)
if (!_M_key_compare(_S_key(__x), __k)) //与find()相同
__y = __x, __x = _S_left(__x);
else
__x = _S_right(__x);
return iterator(__y); //不用比较,如果没有比它小的,__y就是end()
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::const_iterator
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::lower_bound(const _Key& __k) const
{
_Link_type __y = _M_header; /* Last node which is not less than __k. */
_Link_type __x = _M_root(); /* Current node. */
while (__x != 0)
if (!_M_key_compare(_S_key(__x), __k))
__y = __x, __x = _S_left(__x);
else
__x = _S_right(__x);
return const_iterator(__y);
}
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>
::upper_bound(const _Key& __k) //返回第一个大于key的结点
_Link_type __y = _M_header; /* Last node which is greater than __k. */
_Link_type __x = _M_root(); /* Current node. */
while (__x != 0)
if (_M_key_compare(__k, _S_key(__x))) //如果k小于x,有比key大的结点
__y = __x, __x = _S_left(__x);
else
__x = _S_right(__x); //key大于或等于x时,向右走,如果key>所有x,那么__y就是end()
return iterator(__y);
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::const_iterator
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::upper_bound(const _Key& __k) const
{
_Link_type __y = _M_header; /* Last node which is greater than __k. */
_Link_type __x = _M_root(); /* Current node. */
while (__x != 0)
if (_M_key_compare(__k, _S_key(__x)))
__y = __x, __x = _S_left(__x);
else
__x = _S_right(__x);
return const_iterator(__y);
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
inline
pair<typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator,
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator>
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::equal_range(const _Key& __k) //查找key为__k的一个区间
{
return pair<iterator, iterator>(lower_bound(__k), upper_bound(__k));
}
template <class _Key, class _Value, class _KoV, class _Compare, class _Alloc>
inline
pair<typename _Rb_tree<_Key, _Value, _KoV, _Compare, _Alloc>::const_iterator,
typename _Rb_tree<_Key, _Value, _KoV, _Compare, _Alloc>::const_iterator>
_Rb_tree<_Key, _Value, _KoV, _Compare, _Alloc>
::equal_range(const _Key& __k) const
{
return pair<const_iterator,const_iterator>(lower_bound(__k),
upper_bound(__k));
}
可以看到find()函数查找的时候,并不是在查找过程中找到一个key相同的就直接返回了。我们知道左子树都是比根结点小的结点,当相同时,我们再往左子树查找,如果找到,再往左子树查找,这样其实find()返回的就是第一个相同的结点,即在迭代过程中第一个相同的结点。
lower_bound()与find()很类似。但它不用最后比较结点,因为如果这个key大于所有的,那么它在比较的时候会一直向右,那么返回的就是end()。如果它向左走过,就表示有一个key大于等于它了,所以肯定返回的不是end()。
upper_bound()也与find()类似,但是查找第一个大于key的结点。如果x小于或等于key时就向右走,否则向左走。可以看到__M_header的力量真是无穷的。
equal_range()是查找key为k的一段区间,是[lower_bound(), upper_bound()),所以不存在时lower_bound()是与upper_bound()相等的,所以为空。
下面来看看插入的代码,前面和平常的二叉查找树相同,但是由于插入新结点后,可能破坏红黑树的性质,所以在后面对其作了修正。
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::_M_insert(_Base_ptr __x_, _Base_ptr __y_, const _Value& __v)
{
_Link_type __x = (_Link_type) __x_;
_Link_type __y = (_Link_type) __y_;
_Link_type __z;
if (__y == _M_header || __x != 0 || //y==M_header时树为空 __x不为0只存在insert(iteraotr, val)
_M_key_compare(_KeyOfValue()(__v), _S_key(__y))) { //v小于y,为左儿子
__z = _M_create_node(__v); //新建一个结点
_S_left(__y) = __z; // also makes _M_leftmost() = __z
// when __y == _M_header //当树为空时,header->left指向最左
if (__y == _M_header) { //树为空时,向header->parent指向根(现在新增的结点)
_M_root() = __z;
_M_rightmost() = __z; //header->right指向最右结点(现在只有一个根)
}
else if (__y == _M_leftmost()) //看父结点是不是最左结点,如果是,调整最左结点
_M_leftmost() = __z; // maintain _M_leftmost() pointing to min node
}
else {
__z = _M_create_node(__v); //新建一个结点
_S_right(__y) = __z; //为右儿子
if (__y == _M_rightmost()) //如果父结点为最右结点,调整最右结点
_M_rightmost() = __z; // maintain _M_rightmost() pointing to max node
}
_S_parent(__z) = __y; //更新结点信息
_S_left(__z) = 0;
_S_right(__z) = 0;
_Rb_tree_rebalance(__z, _M_header->_M_parent); //调整树结构,使其符合RB-Tree性质
++_M_node_count; //将结点个数+1
return iterator(__z);
}
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 = _M_header;
_Link_type __x = _M_root();
while (__x != 0) {
__y = __x;
__x = _M_key_compare(_KeyOfValue()(__v), _S_key(__x)) ? //v小于x,向左走,否则向右走
_S_left(__x) : _S_right(__x);
}
return _M_insert(__x, __y, __v); //找到位置,插入__x是NULL
}
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) //插入一个值v,不允许重复
{
_Link_type __y = _M_header;
_Link_type __x = _M_root();
bool __comp = true;
while (__x != 0) {
__y = __x;
__comp = _M_key_compare(_KeyOfValue()(__v), _S_key(__x)); //v小于x向左走,否则向左走
__x = __comp ? _S_left(__x) : _S_right(__x);
}
iterator __j = iterator(__y);
if (__comp) //如果__comp为true,表示最后一步中v小于x,即存在一个大于或等于v的结点
return pair<iterator,bool>(_M_insert(__x, __y, __v), true);
else
--__j; //大于或等于它的那个结点
if (_M_key_compare(_S_key(__j._M_node), _KeyOfValue()(__v))) //没有相同的结点时插入
return pair<iterator,bool>(_M_insert(__x, __y, __v), true);
return pair<iterator,bool>(__j, false); //否则直接返回该结点即可
}
template <class _Key, class _Val, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>
::insert_unique(iterator __position, const _Val& __v)
{
if (__position._M_node == _M_header->_M_left) { // begin()
if (size() > 0 &&
_M_key_compare(_KeyOfValue()(__v), _S_key(__position._M_node)))
return _M_insert(__position._M_node, __position._M_node, __v);
// first argument just needs to be non-null
else
return insert_unique(__v).first;
} else if (__position._M_node == _M_header) { // end()
if (_M_key_compare(_S_key(_M_rightmost()), _KeyOfValue()(__v)))
return _M_insert(0, _M_rightmost(), __v);
else
return insert_unique(__v).first;
} else {
iterator __before = __position;
--__before;
if (_M_key_compare(_S_key(__before._M_node), _KeyOfValue()(__v))
&& _M_key_compare(_KeyOfValue()(__v), _S_key(__position._M_node))) {
if (_S_right(__before._M_node) == 0)
return _M_insert(0, __before._M_node, __v);
else
return _M_insert(__position._M_node, __position._M_node, __v);
// first argument just needs to be non-null
} else
return insert_unique(__v).first;
}
}
template <class _Key, class _Val, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::iterator
_Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>
::insert_equal(iterator __position, const _Val& __v)
{
if (__position._M_node == _M_header->_M_left) { // begin()
if (size() > 0 &&
!_M_key_compare(_S_key(__position._M_node), _KeyOfValue()(__v)))
return _M_insert(__position._M_node, __position._M_node, __v);
// first argument just needs to be non-null
else
return insert_equal(__v);
} else if (__position._M_node == _M_header) {// end()
if (!_M_key_compare(_KeyOfValue()(__v), _S_key(_M_rightmost())))
return _M_insert(0, _M_rightmost(), __v);
else
return insert_equal(__v);
} else {
iterator __before = __position;
--__before;
if (!_M_key_compare(_KeyOfValue()(__v), _S_key(__before._M_node))
&& !_M_key_compare(_S_key(__position._M_node), _KeyOfValue()(__v))) {
if (_S_right(__before._M_node) == 0)
return _M_insert(0, __before._M_node, __v);
else
return _M_insert(__position._M_node, __position._M_node, __v);
// first argument just needs to be non-null
} else
return insert_equal(__v);
}
}
#ifdef __STL_MEMBER_TEMPLATES
template <class _Key, class _Val, class _KoV, class _Cmp, class _Alloc>
template<class _II>
void _Rb_tree<_Key,_Val,_KoV,_Cmp,_Alloc>
::insert_equal(_II __first, _II __last) //插入一段区间值
{
for ( ; __first != __last; ++__first)
insert_equal(*__first);
}
template <class _Key, class _Val, class _KoV, class _Cmp, class _Alloc>
template<class _II>
void _Rb_tree<_Key,_Val,_KoV,_Cmp,_Alloc>
::insert_unique(_II __first, _II __last) { //插入一段区间值
for ( ; __first != __last; ++__first)
insert_unique(*__first);
}
#else /* __STL_MEMBER_TEMPLATES */
template <class _Key, class _Val, class _KoV, class _Cmp, class _Alloc>
void
_Rb_tree<_Key,_Val,_KoV,_Cmp,_Alloc>
::insert_equal(const _Val* __first, const _Val* __last)
{
for ( ; __first != __last; ++__first) //插入一段区间值
insert_equal(*__first);
}
template <class _Key, class _Val, class _KoV, class _Cmp, class _Alloc>
void
_Rb_tree<_Key,_Val,_KoV,_Cmp,_Alloc>
::insert_equal(const_iterator __first, const_iterator __last) //插入一段区间值
{
for ( ; __first != __last; ++__first)
insert_equal(*__first);
}
template <class _Key, class _Val, class _KoV, class _Cmp, class _Alloc>
void
_Rb_tree<_Key,_Val,_KoV,_Cmp,_Alloc>
::insert_unique(const _Val* __first, const _Val* __last) //插入一段区间值
{
for ( ; __first != __last; ++__first)
insert_unique(*__first);
}
template <class _Key, class _Val, class _KoV, class _Cmp, class _Alloc>
void _Rb_tree<_Key,_Val,_KoV,_Cmp,_Alloc>
::insert_unique(const_iterator __first, const_iterator __last) //插入一段区间值
{
for ( ; __first != __last; ++__first)
insert_unique(*__first);
}
这么多insert,其实主要的还是_M_insert函数的调用,其余函数先和其它的查找树一样,先找到插入点,然后再进行插入,插入后再调整树结构,使其符合红黑树的性质。注意在_M_insert()中新增加的结点颜色还没有被赋值,它是在_Rb_tree_rebalance()函数中被赋值为红结点,新增加的结点初始颜色都是红色。
在讨论_Rb_tree_rebalance()之前,我们要先来看看两个函数,即左旋和右旋。故名思义,就是对于子结点和其父结点围着边向左旋转或向右旋转。当然,它会改变树结点,但经过调整后它并不会改变查找树的性质,即左子树永远比根结点的值小,右子树的结点不会比根结点小。
看下图:X,Y代表结点,A,B,C代表子树,子树可能为空。
_Rb_tree_rotate_left(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root) //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; //将y放到x的位置
if (__x == __root) //如果x原来是根,现在变成y了
__root = __y;
else if (__x == __x->_M_parent->_M_left) //如果x原来是左儿子
__x->_M_parent->_M_left = __y;
else //原来是右儿子
__x->_M_parent->_M_right = __y;
__y->_M_left = __x; //修改指针
__x->_M_parent = __y;
}
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; //将y的右儿子变为x的左儿子
if (__y->_M_right != 0) //如果不为空,修改父指针
__y->_M_right->_M_parent = __x;
__y->_M_parent = __x->_M_parent; //将y链接到x的parent上
if (__x == __root) //如果x原来为根,现在变成了y
__root = __y;
else if (__x == __x->_M_parent->_M_right) //如果x原来是右儿子
__x->_M_parent->_M_right = __y;
else //x原来为左儿子
__x->_M_parent->_M_left = __y;
__y->_M_right = __x; //修改指针
__x->_M_parent = __y;
}
可以看到,左旋和右旋其实是一对互逆的过程。从图中也可以看到,不论是左旋还中右旋,它们还是满足左子树结点一定比根小,右子树结点一定不比根小的规律。从红黑树的性质来看,当插入一个结点后,唯一可能不满足的条件就是2和3了。2是因为当空树插入一个结点时,因为初始颜色为红,而3就很显然了。现在我们就需要通过从下往上来调整树结构,使其满足其性质。OK,来看看代码:
_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) { //case_1
_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) { //case_2
__x = __x->_M_parent;
_Rb_tree_rotate_left(__x, __root);
}
__x->_M_parent->_M_color = _S_rb_tree_black; //case_3
__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) { //case_4
__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) { //case_5
__x = __x->_M_parent;
_Rb_tree_rotate_right(__x, __root);
}
__x->_M_parent->_M_color = _S_rb_tree_black; //case_6
__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; //根结点颜色一定是黑的
}
OK,看最后一行,性质2满足了。唯一可能不满足的现在就是性质3了。关于调整总共是有六种情况,但这六种情况是对称的,所以总得来说我们分析三种情况就可以了。记住第一个while循环的条件,它结束的条件第一个很好理解,为根的时候父结点是_M_header了,所以就看父结点是红才继续,如果有调整结构的时候我们一直保证红黑树的性,即我们现在不满足的条件就是性质3,那么只有父结点是黑,那么所有条件都是满足的。
这六种情况,我用case_x在代码中表示出来了。先看case_1.case_1调整前后对经如下图:
xp表示x的parent结点,xpp表示x的parent的parent结点
可以看到,它并不改变树结构,只是改变结点颜色,由于它将那个黑色结点下沉,所以其它性质依然不会被破坏,唯一可能不满足的还是性质3,即红结点的儿子结点也有红色的。当时,经过case_1后,结点向上走了两层。
其实case_2与case_3是在一起处理的,从代码中也可以看出来,case_2后,会继续执行case_3,这是因为case_2经过处理刚好与case_3完全一样。case_2, case_3如下图所示:
case_2经过左旋变为case_3时,x还是在同一层上面,而再经过处理后,x的父结点己经是黑色了,也就是while循环条件不满足了,所以从这也可以看出,在RB-Tree调整中,最多经过两次旋转就结束了。case_4,5,6与case_1,2,3就是一个相反的过程了。
最后来看RB Tree最后一个操作——删除,下面这段代码很简单,阅读起来没有问题:
class _Compare, class _Alloc>
void _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::_M_erase(_Link_type __x) //删掉x为根的子树,并不会改变树的性质,故不需要rebalance
{
// erase without rebalancing
while (__x != 0) {
_M_erase(_S_right(__x));
_Link_type __y = _S_left(__x);
destroy_node(__x);
__x = __y;
}
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
void _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::erase(iterator __first, iterator __last) //删除整个迭代区间内结点
{
if (__first == begin() && __last == end())
clear();
else
while (__first != __last) erase(__first++);
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
void _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::erase(const _Key* __first, const _Key* __last) //删除区间内的key
{
while (__first != __last) erase(*__first++);
}
执行删除的代码在这里:
class _Compare, class _Alloc>
inline void _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>
::erase(iterator __position) //删除迭代器指向的结点
{
_Link_type __y =
(_Link_type) _Rb_tree_rebalance_for_erase(__position._M_node,
_M_header->_M_parent,
_M_header->_M_left,
_M_header->_M_right);
destroy_node(__y);
--_M_node_count;
}
template <class _Key, class _Value, class _KeyOfValue,
class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::size_type
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::erase(const _Key& __x) //删除key为x的结点
{
pair<iterator,iterator> __p = equal_range(__x); //把key为x的迭代区间求出来
size_type __n = 0;
distance(__p.first, __p.second, __n);
erase(__p.first, __p.second); //一个一个删除
return __n;
}
上面的代码还是不痛不痒,删除区间的时候是一个一个删除的,在删除的时候我们主要调用的就是_Rb_tree_rebalance_for_erase()函数,它有四个参数,要删除的结点,根,最左结点和最右结点。下面是_Rb_tree_rebalance_for_erase函数的定义。
我们想想平常的二叉查找树中是怎么删除一个结点的:
1. 如果结点至多只有一个子结点,那么将其链接到父结点
2.否则找到其后继结点,先删除后继,再将后继结点的值放到原来要删除的结点中。
恩,很长的一段代码:
_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; //y操作后指向是要删除的结点
_Rb_tree_node_base* __x = 0;
_Rb_tree_node_base* __x_parent = 0;
if (__y->_M_left == 0) //左子树为空时
__x = __y->_M_right; //x指向y的右子树,x可能是NULL
else
if (__y->_M_right == 0) //右子树为空时.
__x = __y->_M_left; //x指向左子树,x一定不为空,前一个判断判断过了
else { //当z的左右子树都不为空时
while (__y->_M_left != 0)
__y = __y->_M_left;
__x = __y->_M_right; //x可能为空
}
if (__y != __z) { //如果y!=z,现在y是原来z的后继
__z->_M_left->_M_parent = __y;
if (__y != __z->_M_right) { //如果后继结点不是z的右儿子
__x_parent = __y->_M_parent; //先将y的parent记录下来
if (__x) __x->_M_parent = __y->_M_parent; //如果x不是NULL,将它指向y的父结点
__y->_M_parent->_M_left = __x; //y原来是左儿子
__y->_M_right = __z->_M_right; //将原来的z的右子树接到y的右子树上面
__z->_M_right->_M_parent = __y;
}
else //如果y=-z,z至少有一个子树为空
__x_parent = __y;
if (__root == __z) //如果要删除的是根
__root = __y; //新根结点
else if (__z->_M_parent->_M_left == __z) //如果原来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 = __z; //y指向最后要删除的结点
// __y now points to node to be actually deleted
}
else { //删除的结点至多只有一个儿子
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) //如果它的右儿子也为空
// makes __leftmost == _M_header if __z == __root
else
__leftmost = _Rb_tree_node_base::_S_minimum(__x); //重新求一次最左结点
if (__rightmost == __z) //如果删除的最右结点(它的右儿子一定为空)
if (__z->_M_left == 0) //它的左儿子也为空
__rightmost = __z->_M_parent; //新的最右结点是它的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) { //case_1
__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)) { //case_2
__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) { //case_3
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; //case_4
__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;
}
同样,从上面那个if (__y->_M_color != _S_rb_tree_red) 之前,操作代码与二叉查找树是一样的,就是判断,再链接。但是这样操作可能会破坏红黑树的性质,所以后面就再做了调整,为什么有这个if判断呢?这是因为如果删除的是一个红结点,RB-Tree的性质还是符合的:
1. 从各点到任何一个叶结点经过的黑结点个数相同(删除之前就满足的条件)
2. 不存在两个相邻的红结点(删除之前满足的条件)
3. 根结点是黑的(原来根结点是黑的,删的是红结点,所以不可能被删除的是根)
由于被删除的结点是一个黑结点,所以任何经过x的路径上的黑结点个数将会少1. 所以我们先x视为还有一重黑色。其改变方法总共是八种,也是两两对称的。根据代码中的case_1,2,3,4,我们直接看图是怎么旋转的(橙色结点表示颜色可能是红色也可能是黑色):
case_1: x的兄弟结点是红色的:
case_2:x的兄弟结点是黑色的,且两个儿子也是黑色的
case_3:x的兄弟结点是红色的,且左儿子是黑色的,右儿子是红色的
case_4:x的兄弟结点是红色的,且右儿子是红色的,左儿子颜色随意
x一直是指向具有双重黑色的结点,它也有一个很好的性质,即最多做三次旋转就会结束。对比上面的图我们可快可以知道红黑的在删除时是怎么维持结点的性质的。
因为红黑树是map, multimap, set, multiset的底层实现,所以上述代码里基本上包含了所有上述操作的集合。代码挺长,想要高效的运用STL,虽然不要通读其源码,但是读源码还是能给人很多好的思路,如红黑树实现中header结点,它使人们对许多特殊情况都不再需要判断了。不过在读STL算法与数据结构的源代码之前,你需要了解的就是STL里的迭代器和内存分配器的原理,这样读起来才不会让人感觉到云里雾里,同时你还需要了解其数据结构的实现原理,这样就能事半功倍了