STL源码剖析——RB-Tree(红黑树)

前言

    有关红黑树的知识在前面博文有介绍,读者可自行往前面博文《红黑树RB-Tree》,《二叉查找树阅读。本文介绍的RB-Tree(红黑树)是来自源码SGI STL中的文件<stl_tree.h>。这里采用了header技巧,header指向根节点的指针,与根节点互为对方的父节点。他们之间的结构如下图所示:


RB-Tree(红黑树)源码剖析

#ifndef __SGI_STL_INTERNAL_TREE_H
#define __SGI_STL_INTERNAL_TREE_H

/*

Red-black tree class, designed for use in implementing STL
associative containers (set, multiset, map, and multimap). The
insertion and deletion algorithms are based on those in Cormen,
Leiserson, and Rivest, Introduction to Algorithms (MIT Press, 1990),
except that

(1) the header cell is maintained with links not only to the root
but also to the leftmost node of the tree, to enable constant time
begin(), and to the rightmost node of the tree, to enable linear time
performance when used with the generic set algorithms (set_union,
etc.);

(2) when a node being deleted has two children its successor node is
relinked into its place, rather than copied, so that the only
iterators invalidated are those referring to the deleted node.

*/
//下面这段话是侯捷老师对上面说明的翻译.
/*

这章讲解Red-black tree(红黑树)class,用来当做SLT关系式容器(如set,multiset,map, 
multimap).里面所用的insertion和deletion方法以Cormen, Leiserson 和 Riveset所著的 
《Introduction to Algorithms》一书为基础,但是有以下两点不同: 
 
(1)header不仅指向root,也指向红黑树的最左节点,以便用常数时间实现begin(),并且也指向红黑树的最右边节点,以便 
set相关泛型算法(如set_union等等)可以有线性时间表现.

(2)当一个即将被删除的节点有两个孩子节点时,它的successor(后继)node is relinked into its place, ranther than copied, 
如此一来唯一失效的(invalidated)的迭代器就只是那些referring to the deleted node.  
*/

/*	
	SGI STL中的RB-Tree实现机制有一定的技巧,定义了一个指向根节点的节点指针header,
并且,header和根节点root互为对方的父节点,header的左子节点指向RB-Tree的最小节点,
header的右子节点指向RB-Tree的最大节点.
*/

/*
RB-Tree是一棵二叉查找树,并且具备有以下性质:
红黑树的性质:
	(1)每个节点或是红色的,或是黑色的.
	(2)根节点是黑色的.
	(3)每个叶节点(NULL)是黑色的.
	(4)如果一个节点是红色的,则它的两个孩子节点都是黑色的.
	(5)对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点.
*/
#include <stl_algobase.h>
#include <stl_alloc.h>
#include <stl_construct.h>
#include <stl_function.h>

__STL_BEGIN_NAMESPACE 

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1375
#endif

typedef bool _Rb_tree_Color_type;//节点颜色类型,非红即黑
const _Rb_tree_Color_type _S_rb_tree_red = false;//红色为0
const _Rb_tree_Color_type _S_rb_tree_black = true;//黑色为1

//RB-Tree节点基本结构
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;//指向右孩子节点

  //RB-Tree最小节点,即最左节点
  static _Base_ptr _S_minimum(_Base_ptr __x)
  {
    
	while (__x->_M_left != 0) __x = __x->_M_left;
    return __x;
  }

  //RB-Tree最大节点,即最右节点
  static _Base_ptr _S_maximum(_Base_ptr __x)
  {
    //一直往RB-Tree的右边走,最右的节点即是最大节点
	//这是二叉查找树的性质
	while (__x->_M_right != 0) __x = __x->_M_right;
    return __x;
  }
};

//RB-Tree节点结构
//继承节点基本结构_Rb_tree_node_base的节点信息
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基本结构
//iterator迭代器的类型为双向迭代器bidirectional_iterator
struct _Rb_tree_base_iterator
{
  typedef _Rb_tree_node_base::_Base_ptr _Base_ptr;//节点指针
  typedef bidirectional_iterator_tag iterator_category;//迭代器类型
  typedef ptrdiff_t difference_type;
  _Base_ptr _M_node;//节点指针,连接容器

	/* 
    重载运算符++和--;目的是找到前驱和后继节点. 
	*/  
  //下面只是为了实现oprerator++的,其他地方不会调用.  
  //RB-Tree的后继节点
  void _M_increment()
  {
    //the right subtree of node x is not empty
	  //【情况1】:存在右子树,则找出右子树的最小节点
	if (_M_node->_M_right != 0) {//如果有右子树
      _M_node = _M_node->_M_right;//向右边走
      while (_M_node->_M_left != 0)//往右子树中的左边一直走到底
        _M_node = _M_node->_M_left;//最左节点就是后继结点
    }
	//the right subtree of node x is empty,and the node of x has a successor node y 
	//没有右子树,但是RB-Tree中节点node存在后继结点
    else {
      _Base_ptr __y = _M_node->_M_parent;//沿其父节点上溯
      while (_M_node == __y->_M_right) { //【情况2】:若节点是其父节点的右孩子,则上溯
        _M_node = __y;					//一直上溯,直到“某节点不是其父节点的右孩子”为止
        __y = __y->_M_parent;
      }
	  /* 
        若此时的右子节点不等于此时的父节点,此时的父节点即为解答,否则此时的node为解答.
		因为SGI STL中的RB-Tree加入的header节点,所以需考虑特殊情况;
        这样做是为了应付一种特殊情况:我们欲寻找根节点的下一个节点,而恰巧根节点无右孩子。 
        当然,以上特殊做法必须配合RB-tree根节点与特殊header之间的特殊关系
      */
	  //以下情况3和情况4是针对header节点的使用,因为根节点和header节点是互为父节点
      if (_M_node->_M_right != __y)//【情况3】:若此时的右子节点不等于此时的父节点
        _M_node = __y;//此时的父节点即为解答
						//【情况4】:否则此时的node为解答 
    }
  }

  //下面只是为了实现oprerator--的,其他地方不会调用.  
  //RB-Tree的前驱节点
  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;			 //【情况1】:右子节点即为解答。
	/* 
      以上情况发生于node为header时(亦即node为end()时)。注意,header之右孩子即 
      mostright,指向整棵树的max节点。 
      */ 
    else if (_M_node->_M_left != 0) {//若有左孩子节点。【情况2】:左子树的最大值即为前驱节点
      _Base_ptr __y = _M_node->_M_left;//向左边走,即令y指向左孩子
      while (__y->_M_right != 0)//y存在右孩子,
        __y = __y->_M_right;//一直往右走到底
      _M_node = __y;//最后即为解答
    }
    else {//即非根节点,且没有左孩子节点,【情况3】
      _Base_ptr __y = _M_node->_M_parent;//找出父节点
      while (_M_node == __y->_M_left) {//node节点是其父节点的左孩子
        _M_node = __y;//一直交替上溯
        __y = __y->_M_parent;//直到不为左孩子结点
      }
      _M_node = __y;//此时父节点即为解答
    }
  }
};

//RB-Tree的迭代器iterator结构
//继承基类迭代器Rb_tree_base_iterator
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_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 */

  //前缀operator++找出后继节点,调用基类的_M_increment()
  _Self& operator++() { _M_increment(); return *this; }
  //后缀operator++找出后继节点,调用基类的_M_increment()
  _Self operator++(int) {
    _Self __tmp = *this;
    _M_increment();
    return __tmp;
  }
    
  //前缀operator--找出前驱节点,调用基类的_M_decrement()
  _Self& operator--() { _M_decrement(); return *this; }
  //后缀operator--找出前驱节点,调用基类的_M_decrement()
  _Self operator--(int) {
    _Self __tmp = *this;
    _M_decrement();
    return __tmp;
  }
};

//两个迭代器相等,意味着指向RB-Tree的同一个节点
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;
  //两个迭代器不相等,意味着所指向的节点不同
}

#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION

inline bidirectional_iterator_tag
iterator_category(const _Rb_tree_base_iterator&) {
  return bidirectional_iterator_tag();
}

inline _Rb_tree_base_iterator::difference_type*
distance_type(const _Rb_tree_base_iterator&) {
  return (_Rb_tree_base_iterator::difference_type*) 0;
}

template <class _Value, class _Ref, class _Ptr>
inline _Value* value_type(const _Rb_tree_iterator<_Value, _Ref, _Ptr>&) {
  return (_Value*) 0;
}

#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

// 以下都是全域函式:__rb_tree_rotate_left(), __rb_tree_rotate_right(),  
// __rb_tree_rebalance(), __rb_tree_rebalance_for_erase()  
  
//新节点必须为红色节点。如果安插处的父节点为红色,就违反了红黑色规则
//此时要旋转和改变颜色 

//左旋转
//节点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的右孩子y
  __x->_M_right = __y->_M_left;//把y节点的左孩子作为旋转节点x的右孩子
  if (__y->_M_left !=0)
    __y->_M_left->_M_parent = __x;//更新节点y左孩子父节点指针,指向新的父节点x
  __y->_M_parent = __x->_M_parent;//y节点替换x节点的位置

  //令y完全顶替x的地位(必须将x对其父节点的关系完全接收过来)
  if (__x == __root)//若原始位置节点x是根节点
    __root = __y;//则y为新的根节点
  //否则,若x节点是其父节点的左孩子
  else if (__x == __x->_M_parent->_M_left)
    __x->_M_parent->_M_left = __y;//则更新节点y为原始x父节点的左孩子
  else//若x节点是其父节点的右孩子
    __x->_M_parent->_M_right = __y;//则更新节点y为原始x父节点的右孩子
  __y->_M_left = __x;//旋转后旋转节点x作为节点y的左孩子
  __x->_M_parent = __y;//更新x节点的父节点指针
}

//右旋转
//节点x为右旋转点
inl
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值