STL源码:红黑树

红黑树的性质和插入操作

这部分参考文章 《红黑树操作及实现》

红黑树节点结构

typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;     // 红色为0
const __rb_tree_color_type __rb_tree_black = true; // 黑色为1

struct __rb_tree_node_base
{
  typedef __rb_tree_color_type color_type;
  typedef __rb_tree_node_base* base_ptr;

  color_type color;     // 节点颜色,红色或黑色
  base_ptr parent;      // 该指针指向其父节点
  base_ptr left;        // 指向左节点
  base_ptr right;       // 指向右节点

  //二叉树搜索树,一直向左走,找到最小的值
  static base_ptr minimum(base_ptr x)
  {
	 while (x->left != 0) x = x->left; 
	 return x;                            
  }

  //二叉搜索树,一直向右走,找最大的值
  static base_ptr maximum(base_ptr x)
  {
    while (x->right != 0) x = x->right; 
    return x;                           
  }
};

template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
  typedef __rb_tree_node<Value>* link_type;
  Value value_field;   //节点的值
};
红黑树节点的结构如下:

红黑树的迭代器

RB-tree迭代器实现分为两层,这种设计理念类似于slist。下图是两层节点结构和双层迭代器结构间的关系,其中主要意义是:__rb_tree_node继承自__rb_tree_node_base,__rb_tree_iterator继承自__rb_tree_base_iterator。

         这里主要关注底层迭代器increment()和decrement()这两个操作分别实现迭代器的自加和自减操作,其前进后退举动完全依据二叉搜索树寻找前驱后继节点的规则(二叉搜索树寻找前驱后继规则参考该文章),只是多了一些实现技巧

        代码的实现见最后的完整源代码。这里的实现技巧如下。每当插入新节点时,不但要依据红黑树规则来调整,还有维护header的正确性,使其父节点指向根节点,左子节点指向最小节点,右子节点指向最大节点。

红黑树插入操作

        提供了两种插入操作:insert_unique()和insert_equal(),分别在树中插入独一无二的值、插入可以重复的值。有多个版本,重点分析insert_unique(const Value& v)版本。

真正指向插入操作的是__insert()函数。


红黑树源码

//stl_tree.h
#ifndef __SGI_STL_INTERNAL_TREE_H
#define __SGI_STL_INTERNAL_TREE_H


/*
Red-black tree(红黑树)class,用来当做SLT关联容器的底层机制(如set,multiset,map,
multimap)。里面所用的insertion和deletion方法以Cormen, Leiserson 和 Riveset所著的
《算法导论》一书为基础,但是有以下两点不同:

(1)header不仅指向root,也指向红黑树的最左节点,以便用常数时间实现begin(),并且也指向红黑树的最右边节点,以便
set相关泛型算法(如set_union等等)可以有线性时间实现。
(2)当一个即将被删除的节点有两个孩子节点时,它的successor(后继)node is relinked into its place, ranther than copied,
如此一来唯一失效的(invalidated)的迭代器就只是那些referring to the deleted node.
*/
#include <stl_algobase.h>
#include <stl_alloc.h>
#include <stl_construct.h>
#include <stl_function.h>

__STL_BEGIN_NAMESPACE 
//定义红色黑色。红色为0,黑色为1
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;
//红黑树Base类
struct __rb_tree_node_base
{
  typedef __rb_tree_color_type color_type;
  typedef __rb_tree_node_base* base_ptr;

  color_type color; 	// 节点颜色,红或者黑
  base_ptr parent;  	// RB树的许多操作,必须知道其父结点
  base_ptr left;	  	// 指向左孩子节点。
  base_ptr right;   	// 指向右孩子节点。

  static base_ptr minimum(base_ptr x)
  {
    while (x->left != 0) x = x->left;	// 一直向左走,就会找到最小值
    return x;							// 这是二叉查找树的性质。同理下面的函数
  }

  static base_ptr maximum(base_ptr x)
  {
    while (x->right != 0) x = x->right;
    return x;
  }
};

//红黑树类,继承Base类
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
  typedef __rb_tree_node<Value>* link_type;//指向节点的指针
  Value value_field;	// 节点的值
};
//迭代器基类,类型为bidirectional_iterator_tag,可以双向移动
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 node;

  /*
	重载运算符++和--。目的是找到前驱和后继节点。
	关于前驱和后继节点的定义,类似二叉查找树。可以在这里找到:
	http://blog.csdn.net/u013074465/article/details/41699891
  */
  //下面只是为了实现oprerator++的,其他地方不会调用了。
  //++是找到其后继节点
  void increment()
  {
	//如果有右孩子,就是找右子树的最小值
    if (node->right != 0) {		// 如果有右孩子
      node = node->right;		// 就向右走
      while (node->left != 0)	// 然后向左走到底
        node = node->left;		
    }
	//如果无右子树。那么就找其最低祖先节点,且这个最低祖先节点的左孩子节点
	//也是其祖先节点(每个节点就是自己的祖先节点)
    else {					// 没有右孩子
      base_ptr y = node->parent;	// 找出父节点
      while (node == y->right) {	// 如果现行节点本身是个右子节点
        node = y;				// 就一直上溯,直到「不为右子节点」止。
        y = y->parent;
      }
	  /*
		若此时的右子节点不等于此时的父节点,此时的父节点即为解答,否则此时的node为解答.
		这样做是为了应付一种特殊情况:我们欲寻找根节点的下一个节点。而恰巧根节点无右孩子。
		当然,以上特殊做法必须配合RB-tree根节点与特殊header之间的特殊关系,在上面有图
	  */
      if (node->right != y)		// 若此时的右子节点不等于此时的父节点
        node = y;				// 此时的父节点即为解答
                                // 否则此时的node为解答
    }						
  
  }

   //查找前驱结点。
  void decrement()
  {
    if (node->color == __rb_tree_red &&	// 如果是红节点,且
        node->parent->parent == node)		// 父节点的父节点等于自己
      node = node->right;				// 状况(1) 右子节点即为解答。
	  /*
	  以上情况发生于node为header时(亦即node为end()时)。注意,header之右孩子即
	  mostright,指向整棵树的max节点。上面有图
	  */
	//左子树的最大值结点
    else if (node->left != 0) {	
      base_ptr y = node->left;
      while (y->right != 0)	
        y = y->right;	
      node = y;		
    }
	/*
	既非根节点,且无左子树。找其最低祖先节点y,且y的右孩子也是其祖先节点
	*/
    else {							
      base_ptr y = node->parent;			//找出父节点
      while (node == y->left) {	
        node = y;					
        y = y->parent;	
      }
      node = y;
    }
  }
};
//此处为迭代器
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) { node = x; }
  __rb_tree_iterator(const iterator& it) { node = it.node; }

  //重载操作符
  reference operator*() const { return link_type(node)->value_field; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

	//++做了封装,调用的是increment()
  self& operator++() { increment(); return *this; }
  self operator++(int) {
    self tmp = *this;
    increment();
    return tmp;
  }
    //调用的是decrement
  self& operator--() { decrement(); return *this; }
  self operator--(int) {
    self tmp = *this;
    decrement();
    return tmp;
  }
};
//两个迭代器相等,意味着它们指向同一个红黑树节点
inline bool operator==(const __rb_tree_base_iterator& x,
                       const __rb_tree_base_iterator& y) {
  return x.node == y.node;
}

inline bool operator!=(const __rb_tree_base_iterator& x,
                       const __rb_tree_base_iterator& y) {
  return x.node != y.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()

/*
新节点必须为红色节点。如果安插处的父节点为红色,就违反了红黑色规则(3)。此时要旋转和改变颜色
*/
//左旋转
inline void 
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
  // x 为旋转点
  __rb_tree_node_base* y = x->right;	// y为x的右孩子
  x->right = y->left;
  if (y->left !=0)
    y->left->parent = x;		// 不要忘了回马枪设置父节点
  y->parent = x->parent;

  // 令 y 完全顶替 x 的地位(必须将x对其父节点的关系完全接收过来)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值