STL源码剖析_读书笔记:第五章 关联式容器 红黑树篇

关联式容器

实现:红黑树,按照键值大小将元素放于适当位置

内部结构:平衡二叉树

含义:每个元素都有键值与实值

二叉搜索树:对数时间的元素插入和访问,节点键值大于左子树中每个节点键值,小于右子树中每个节点键值

平衡二叉树:任意节点的左右子树的高度之差的绝对值<=1

4种不平衡状况:

1)左子节点左子树插入:左旋即可

2)右子节点右子树插入右旋即可

3)左子节点右子树插入先左后右旋转即可

4)右子节点左子树插入:先右后左旋转即可

1),2)属于外侧插入,3),4)属于内侧插入

 

 

红黑树:

条件:

1每个节点不是红色就是黑色

2根节点为黑色   

3若节点为红,其子节点必为黑色                         :新增节点的父节点必须为黑

4任一节点至NULL(树尾端)的任何路径,所含黑节点之数必须相同  :新增节点必为红(把其当为子节点)

注意,并没有说明若节点为黑,子节点为红,如果是这样就变成红黑相间了

4种插入情形:

1)       S为黑,且X为外侧插入:单旋P,G,再更改P,G颜色

2)       S为黑,且X为内侧插入:单旋P,G,更改G,X颜色,再将结果对G单旋,

3)       S为红,且X为外侧插入,且GG为黑:单旋P,G,更改X的颜色

4)       S为红,且X为外侧插入,且GG为红:单旋P,G,更改X的颜色,持续上述过程,直至不再有父子连续为红情况

 

解决4)连续上行调整的方法:采用由上而下程序:

思路:设新增节点为A,沿着A的路径,只要看到有某节点X的两个子节点都为红色,就把X改为红色,并把两个子节点改为黑色。

 

 

RB-tree:使用双层节点结构和双层迭代器结构。

_rb_tree_node继承自_rb_tree_node_base,_rb_tree_iterator继承自_rb_tree_base_iterator

 

RB_tree迭代器:

性质:双向迭代器,但不能随机存取

 

 

RB_tree构造方式:

1)  复制现有红黑树产生新的红黑树

2)  产生空树

 

RB_tree插入方式:

1)       insert_equal:插入新值,节点键值允许重复

2)       insert_unique:插入键值必须唯一

 

下面是红黑树部分重要函数的实现

#include<iostream>
#include<string>
#include<vector>
#include<iterator>

using namespace std;

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 minimun(base_ptr x)
 {
  while(x->left!=0)
  {
   x = x->left;
  }
  return x;
 }

 //一直向右走,获取最大值节点
 static base_ptr maxmimum(base_ptr x)
 {
  while(x->right!=0)
  {
   x = x->right;
  }
  return x;
 }
};

//红黑树派生类节点
template<typename Value>
struct _rb_tree_node : public _rb_tree_node_base
{
 typedef _rb_tree_node<Value>* link_type;
 Value value_field;//节点值
};

//红黑树基类迭代器
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;//用来与容器之间产生连接关系

 void increment()
 {
  if(0!=node->right)//如果有右孩子
  {
   node = node->right;//向右走
   while(0!=node->left)//一直走到该右孩子的左子树底部
   {
    node = node->left;
   }
  }
  else//没有右孩子
  {
   base_ptr p = node->parent;//找到父节点
   while(node==p->right)//如果当前节点为父节点的右孩子
   {
    node = p;//一直向上寻找,直到当前节点不是父节点的右孩子
    p = node->parent;
   }

   //特殊情形:寻找根节点的下一节点,而根节点无右节点
   if(node->right!=p)//如果此时的右子节点不等于此时的父节点。
   {
    node = p;//则此时的父节点即为下一个要访问的对象
   }
   //否则此时的node就是下一个要访问的对象
  }
 }

 void decrement()
 {
  //如果是红节点且父节点的父节点为自己(节点为头节点或尾节点),则右节点就是退一步要访问的对象
  if(node->color==_rb_tree_red && node->parent->parent==node)
  {
   node = node->right;
  }
  //如果有左孩子,上一个访问的节点是为左孩子的右子树的底部
  else if(0!=node->left)//如果有左孩子
  {
   base_ptr p = node->left;
   while(0!=p->right)
   {
    p = p->right;
   }
   node = p;
  }
  //既不是根节点,也没有左孩子,则向上追溯到当前节点不是父节点的左节点时,该节点的父节点就上上一个访问的节点
  else
  {
   base_ptr p = node->parent;
   while(node==p->left)
   {
    node = p;
    p = p->parent;
   }
   node = p;
  }
 }
};

//红黑树派生类迭代器
template<typename Value,typename Ref,typename 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;}
#ifdef _SGI_STL_NO_ARROW_OPERAATOR
 pointer operator->() const {return &(operator*());}
#endif
 self ++operator++() {increment();return *this;}
 self operator++(int){self temp = *this;increment();return temp;}
 operator--();
 operator--(int);
};

//红黑树类
template<class Key,class Value,class KeyOfValue,class Compare,class Alloc>
class rb_tree
{
protected:
 typedef void* void_pointer;
 typedef _rb_tree_node_base* base_ptr;
 typedef _rb_tree_node<Value> rb_tree_node;
 typedef simple_alloc<rb_tree_node,Alloc> rb_tree_node_allocator;
 typedef _rb_tree_color_type color_type;

public:
 typedef Key key_type;
 typedef Value value_type;
 typedef value_type* pointer;
 typedef const value_type* const_pointer;
 typedef const value_type& reference;
 typedef const const value_type& const_reference;
 typedef _rb_tree_node* link_type;
 typedef size_t size_type;
 typedef ptrdiff_t difference_type;

protected:
 link_type get_node(){return _rb_tree_node_allocator::allocate();}
 void put_node(link_type p){rb_tree_node_allocator::deallocate(p);}
 link_type create_node(const value_type& x)
 {
  link_type temp = get_node();//分配空间
  _STL_TRY
  {
   construct(&temp->value_field,x);//构造内容
  }
  _STL_UNWIND(put_node(temp));
  return temp;
 }

 //复制一个节点(值与颜色)
 link_type clone_node(link_type)
 {
  link_type temp = create_node(x->value_field);
  temp->color = x->color;
  temp->right = 0;
  temp->left = 0;
  return temp;
 }

 void destry_node(link_type x)
 {
  destroy(&x->value_field);//析构内容
  put_node(p);//释放内存
 }

protected:
 size_type node_count;//树的大小=节点数量
 link_type header;
 Compare key_compare;

 //取得header成员
 link_type& root() const {return (link_type&)header->parent;}
 link_type& leftmost() const {return (link_type&)header->left;}
 link_type& rightmost() const {return (link_type&)header->right;}

 //取得节点x的成员
 static link_type& left(link_type x){return (link_type)x->left;}
 static link_type& right(link_type x){return (link_type)x->right;}
 static link_type& parent(link_type x){return (link_type)x->parent;}

 static reference value(link_type x){return x->value_field;}
 static const Key& key(link_type x){return KeyOfValue()value(x);}//?
 static color_type& color(link_type x){return (color_type&)x->color;}

private:
 //header节点是根节点的父节点
 void init()
 {
  header = get_node();//产生节点空间,令header指向它
  color(header) = _rb_tree_red;//令header为红色,区分root
  root() = 0;
  leftmost() = header;//令header左孩子为自己
  rightmost() = header;//令header右孩子为自己
 }
public:
 //作用:插入节点,节点键值允许重复。返回值:红黑树的迭代器,指向新节点
 typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator
  insert_equal(const Value& v)
 {
  link_type y = header;
  link_type x = root;
  while(0!=x)
  {
   y = x;
   x = key_compare(KeyOfValue()(v),key(x)?left(x):right(x));//遇大往左,否则往右
  }
  return _insert(x,y,v);//x为插入节点,y为插入节点的父节点,v为键值
 }

 //作用:插入节点,节点键值不允许重复。返回:是一个pair,第一个元素为红黑树的迭代器,指向新节点,第二元素表示插入成功与否
 pair< typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator,bool>
  insert_unique(const Value& v)
 {
  link_type y = header;
  link_type x = root();//从根节点开始
  bool comp = true;
  while(0!=x)//从根节点往下寻找插入点
  {
   y = x;
   comp = key_compare(KeyOfValue()(v),key(x));//v的键值与当前节点键值进行比较
   x = comp ? left(x) : right(x);//v的键值<=当前节点键值,则向左
  }
  //此时y必为插入节点的父节点
  iterator j = iterator(y);//令迭代器指向插入节点的父节点
  if(comp)//如果v的键值>当前节点键值,则向右
  {
   if(begin()==j)//若插入节点的父节点为最左节点
   {
    return pair<iterator,bool>(_insert(x,y,v),true);
   }
   else//插入节点的父节点不为最左节点
   {
    --j;//调整迭代器,回头准备测试
   }
   if(key_compare(Key(j.node),KeyOfValue()(v)))//如果J的键值>当前节点键值,则向右
   {
    return pair<iterator,bool>(_insert(x,y,v),true);
   }
   //如果走到这里,表示键值重复
   return pair<iterator,bool>(j,false);
  }
 }
//真正的插入执行程序
 typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator
  _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==header || x!=0 || key_compare(KeyOfValue()(v),key(y)))
  {
   z = create_node(v);//产生新节点
   left(y) = z;//当y为根节点的父节点时,leftmost()=z
   if(y==header)
   {
    root() = z;
    rightmost() = z;
   }
   else if(leftmost()==y)//如果y为最左节点 ?
   {
    leftmost() = z;//维护leftmost(),使它永远指向最左节点
   }
   else
   {
    z = create_node(v);//产生新节点
    right(y) = z;//令新节点成为插入节点父节点的右孩子
    if(rightmost()==y)
    {
     rightmost() = z;//维护rightmost(),使它永远指向最右节点
    }
   }
   //设定新节点的父节点和左右孩子
   parent(z) = y;
   left(z) = 0;
   right(z) = 0;
   _rb_tree_reblance(z,header->parent);//传入新增节点和根节点进行平衡处理
   ++node_count;
   return iterator(z);//返回迭代器,指向新节点
  }
 }
}


int main(int argc,char *argv[])
{
 cout<<"红黑树的原理"<<endl;
 getchar();
 return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值