rb_tree是一种特殊的平衡二叉搜索树,但是其对平衡的要求比avl_tree低,avl_tree要求左右子树的高度差不能大于1,而rb_tree只要求从一个节点至树的尾端的任何路径的黑节点的个数相等

rb_tree必须满足的规则

1.每个节点不是黑色就是红色;
2.根节点必须为黑色;
3.若节点为红色,则其子节点必须为黑色(红不连);
4.任意节点至树尾端的任何路径的黑色节点的个数必须相等;

总结一下,也就是——>一头一脚黑, 黑同红不连

为何要用rb_tree, avl_tree:

rb_tree, avl_tree都可以实现平衡二叉搜索树,它们都比一般的(无法绝对维持平衡的)二叉搜索树复杂,因此其插入和删除节点的平均时间也比较长但是它们可以避免极难处理的高度不平衡情况,因为它们总是维持着某种平衡(即每插入一个节点就会判断树是否平衡,不平衡就调整),所以其元素的访问(搜寻)时间平均来说比较少.

rb_tree的节点设计—->rb_tree节点设计分两层,node_base和node,node_base主要负责红黑树的连接部分 (parent,left,right),而node负责红黑树的数据部分(value_filed节点值)

struct __rb_tree_node_base
{typedef __rb_tree_color_type color_type;     //节点颜色typedef __rb_tree_node_base* base_ptr;       //父节点指针//rb树的父节点的成员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;}
};//rb树的节点
template<class Value>
struct __rb_tree_node : public __rb_tree_node_base
{typedef __rb_tree_node<Value>* link_type;   //rb树的节点指针Value value_filed;    //rb树的节点的值
};

rb_tree的迭代器设计—>rb_tree的迭代器也设计为两层,base_iterator和iterator

//rb树的迭代器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(node->right != 0){   //若当前节点的右树不空,则其直接前驱就在其右树部分node = node->right;   //在node的右树中找出最左的节点就是node的直接前驱while(node->left != 0){node = node->left;}}else{    //node的右树为空,则进行上溯查找node的父节点,直到找到node的直接前驱base_ptr y = node->parent;while(node == y->right){node = y;y = y->parent;}if(node->right != y){node = y;}}}//指向上一个节点(--操作)void decrement(){if(node->color == __rb_tree_red && node->parent->parent == node){  //node为headernode = node->right;}else if(node->left != 0){   //若node的左树不为空,就在左树中找到最右侧的节点base_ptr y = node->left;while(y->right != 0){y = y->right;}node = y;}else{    //node的左树为空,则上溯,查找node的父节点,找到node的直接前驱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_filed;}pointer operator->()const{return &(operator*());}self& operator++(){increment();return *this;}self operator++(int){self tmp = *this;increment();return tmp;}self& operator--(){decrement();return *this;}self operator--(int){self tmp = *this;decrement();return tmp;}
};

rb_tree的无论是节点还是迭代器都是以struct定义的原因是: struct的所有成员都是public,所以其所有成员都可被外界自由取用

rb_tree的实现使用了一个技巧,那就是使用了header

rb_tree的数据结构

//rb树
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
class rb_tree{
protected:typedef void* void_pointer;typedef __rb_tree_node_base* base_ptr;   //rb树的父节点指针typedef __rb_tree_node<Value> rb_tree_node;   //rb树的节点typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;   //以节点的大小为配置单位typedef __rb_tree_color_type color_type;   //rb树的节点的颜色public:typedef Key key_type;typedef Value value_type;typedef value_type* pointer;typedef const value_type* const_pointer;typedef value_type& reference;typedef const value_type& const_reference;typedef rb_tree_node* link_type;    //rb树的节点指针typedef size_t size_type;typedef ptrdiff_t difference_type;protected:link_type get_node(){return rb_tree_node_allocator::allocate();}link_type create_node(const value_type& x){link_type tmp = get_node();construct(&tmp->value_filed, x);return tmp;}link_type clone_node(link_type x){link_type tmp = create_node(x->value_filed);tmp->color = x->color;tmp->left = 0;tmp->right = 0;return tmp;}void destroy_node(link_type p){destroy(&p->value_filed);put_node(p);}protected:size_type node_count;   //rb树的节个数link_type header;       //rb树的头指针,相当于链表的第一个空节点Compare key_compare;    protected: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;}protected: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_filed;}static const Key& key(link_type x){return KeyOfValue()(value(x));}static color_type& color(link_type x){return (color_type&)(x->color);}static link_type& left(base_ptr x){return (link_type&)(x->left);}static link_type& right(base_ptr x){return (link_type&)(x->right);}static link_type& parent(base_ptr x){return (link_type&)(x->parent);}static reference value(base_ptr x){return ((link_type)x)->value_filed;}static const Key& key(base_ptr x){return KeyOfValue()(value(link_type(x)));}static color_type& color(base_ptr x){return (color_type&)(link_type(x)->color);}static link_type minimum(link_type x){return (link_type) __rb_tree_node_base::minimum(x);}static link_type maximum(link_type x){return (link_type) __rb_tree_node_base::maximum(x);}public:typedef __rb_tree_iterator<value_type, reference, pointer> iterator;typedef __rb_tree_iterator<value_type, const_reference, const_pointer> const_iterator;private:void init(){header = get_node();    //配置一个节点color(header) = __rb_tree_red;   //将header节点设为红色root() = 0; //将header的父节点赋空leftmost() = header;   //将header指向最左的节点rightmost() = header;  //将header指向最右的节点}public:rb_tree(const Compare& comp = Compare()) : node_count(0), key_compare(comp){init();   //生成一个空节点header}public:iterator begin(){return leftmost();}iterator end(){return header;}public:pair<iterator, bool> insert_unique(const value_type& x);protected:iterator __insert(base_ptr x_, base_ptr y_, const Value& v);
};

红黑树的插入:根据插入的节点的位置,以及其外围节点(s伯父节点,GG曾祖父节点)的颜色,会出现以下四种状况:
(先作以下假设:假设x为新插入的节点,p为其父节点,G为其祖父节点,S为其伯父节点,GG为其曾祖父节点)

状况一:
S为黑色并且x为外侧插入,此时要先对P, G作一次单旋转,再更改P,G的颜色,就可满足红黑树的规则。

状况二: S为黑色并且x为内侧插入;要先对P,X作一次单旋转,再更改G,X的颜色,最后将所得结果再对G作一次单旋转,就可以满足红黑树的规则。

状况三:S为红色并且X为外侧插入;先对P,G作一次单旋转,再改变X
的颜色,若此时的GG为黑色,则树是平衡的,若不是,则要继续上溯,判断树的平衡性并调整。

状况四:S为红色并且X为内侧插入;先对P,G作一次单选装,改变X的颜色,此时若GG为红色,就要继续往根的方向走,直到不在有父子节点连续为红色的状况。

红黑树的插入操作:

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)
{link_type y = header;link_type x = root();   //从根开始bool comp = true;//从根开始查找,得到插入节点的位置while(x != 0){y = x;comp = key_compare(KeyOfValue()(v), key(x));    //比较大小,若v小于x则comp为truex = comp ? left(x) : right(x);    //comp为true则x要插入左树,fouze是右树}//while结束,y就是要插入节点的父节点,此时y必为叶子节点iterator j = iterator(y);   //迭代器j指向插入节点的父节点if(comp){   //while结束,若comp为true,则在左侧插入if(j == begin()){   //若插入点的父节点为最左侧的节点//x为插入点,y为插入点的父节点,v要插入的值return pair<iterator, bool>(__insert(x, y, v), true);}else{   //插入点的父节点不为最左节点--j; //回溯判断插入的新值是否符合该树的当前节点没有和其值一样的,因Comp用的是判断小于,所以有可能相等}}if(key_compare(key(j.node), KeyOfValue()(v))){   //若j所指的节点的值小于v,则在右侧插入//x为插入点,y为插入点的父节点,v要插入的值return pair<iterator, bool>(__insert(x, y, v), true);   }//此时,说明新值x与树中的健值重复,不进行插入return pair<iterator, bool>(j, false);
}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(base_ptr x_, base_ptr y_, const Value& v)
{//x_为插入点,y_为插入点的父节点,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);   //配置一个新节点,z就成为要插入的节点left(y) = z;     //若y==header时,leftmost() = zif(y == header){   //若y为header空节点,则z就为根结点,也为最右节点root() = z;rightmost() = z;}else if(y == leftmost()){   //若y为最左节点,则新插入的节点就变成最左节点leftmost() = z;}}else{z = create_node(v);    //配置一个节点zright(y) = z;          //使z成为插入点x的父节点y的右节点if(y == rightmost()){   //若y为最右节点,则z就是新的最右节点rightmost() = z;}}//调整z的父节点和z的左右节点parent(z) = y;left(z) = 0;right(z) = 0;__rb_tree_rebalance(z, header->parent);  //调整z节点一直上溯到根结点的平衡++node_count;     //节点数增加return iterator(z);   //返回一个迭代器,指向新增节点
}

插入节点所需的调整平衡的函数

//x为新插入节点,root为根结点
inline void __rb_tree_rebalance(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{x->color = __rb_tree_red;   //新插入节点的颜色为红色while(x != root && x->parent->color == __rb_tree_red){   //父节点为红色,就不平衡需要调整//整体左侧插入if(x->parent == x->parent->parent->left){   //父节点为祖父节点的左节点__rb_tree_node_base* y = x->parent->parent->right;  //y为x的叔伯节点if(y && y->color == __rb_tree_red){  //伯父节点存在,并且伯父节点为红色x->parent->color = __rb_tree_black;    //将x的父节点变黑色y->color = __rb_tree_black;     //将x的伯父节点变为黑色x->parent->parent->color = __rb_tree_red;  //将x的祖父节点变为红色,此时要上溯查看其曾祖父节点的颜色,若为红则不平衡要调整x = x->parent->parent;   //继续上溯查找不平衡并调整平衡}else{    //没有伯父节点或伯父节点为黑色(没有时默认黑色)if(x == x->parent->right){    //内侧插入x = x->parent;//先进行左旋__rb_tree_rotate_left(x, root);}//或是左侧插入,直接进行右旋即可x->parent->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;//再进行右旋__rb_tree_rotate_right(x->parent->parent, root);}}//整体右侧插入else{__rb_tree_node_base* y = x->parent->parent->left;    //y为x的伯父节点if(y && y->color == __rb_tree_red){    //伯父节点存在并为红色,插入节点又为红色,所以黑色节点不平衡x->parent->color == __rb_tree_black;   //改变父节点的颜色y->color = __rb_tree_black;   //改变伯父节点的颜色x->parent->parent->color = __rb_tree_red;  //改变祖父节点的颜色为红色,则其曾祖父节点可能为红色,要上溯进行查看调整x = x->parent->parent;   //继续上溯查找不平衡点并调整}else{    //伯父节点不存在或伯父节点为黑色if(x == x->parent->left){    //内侧插入x = x->parent;//先进行右旋__rb_tree_rotate_right(x, root);}//或是右侧插入,直接进行左旋x->parent->color = __rb_tree_black;  //改变父节点和祖父节点的颜色x->parent->parent->color = __rb_tree_red;//再进行左旋__rb_tree_rotate_left(x->parent->parent, root);}}}//将根结点的颜色置为黑色root->color = __rb_tree_black;
}//左旋
inline void __rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{__rb_tree_node_base* y = x->right;   //y为旋转点x的右节点x->right = y->left;     //左旋要将x的右节点的左树挂接到y的右树部分if(y->left != 0){y->left->parent = x;  //改变y的左树的父节点指向}y->parent = x->parent;   //改变y的父节点//对x和y作旋转if(x == root){   //若新插入的节点为根结点,则让x的右节点y作根结点root = y;}else if(x == x->parent->left){  //若x是其父节点的左节点,则让x的右节点y作其父节点的左节点x->parent->left = y;}else{  //x是其父节点的右节点,则让x的右节点作其父节点的右节点x->parent->right = y;}//更改指向y->left = x;x->parent = y;
}//右旋
inline void __rb_tree_rotate_right(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{__rb_tree_node_base* y = x->left;   //y为x的左节点x->left = y->right;   //将x旋转下来,y旋转上去,将y的右节点给予x的左节点if(y->right != 0){  //若y的右节点不空,更改其父节点指向y->right->parent = x;}y->parent = x->parent;   //更改y的父节点//对x和y进行旋转if(x == root){root = y;}else if(x == x->parent->right){x->parent->right = y;}else{x->parent->left = y;}y->right = x;x->parent = y;
}

SGI STL的rb_tree浅析相关推荐

  1. SGI STL 内存分配方式及malloc底层实现分析

    在STL中考虑到小型区块所可能造成的内存碎片问题,SGI STL设计了双层级配置器,第一级配置器直接使用malloc()和free();第二级配置器则视情况采用不同的策略:当配置区块超过128byte ...

  2. sgi stl 之list

    sgi stl 的list实际上是一个双向环形链表 下面是代码 #ifndef C_LIST_H #define C_LIST_H #include "cconstruct.h" ...

  3. SGI STL 学习笔记二 vector

    sequence containers Array Vector Heap Priority_queue List sList(not in standard) Deque Stack Queue S ...

  4. 栈与队列在SGI STL的底层实现

    栈 栈提供push和pop等接口,不提供走访功能,也不提供迭代器. STL中栈不被归类为容器,而被归类为container adapter(容器适配器),这是因为栈是以底层容器完成其所有的工作,对外提 ...

  5. 【STL深入学习】SGI STL空间配置器详解(二)-第二级空间配置器

    本文讲解SGI STL空间配置器的第二级配置器. 相比第一级配置器,第二级配置器多了一些机制,避免小额区块造成内存的碎片.不仅仅是碎片的问题,配置时的额外负担也是一个大问题.因为区块越小,额外负担所占 ...

  6. 【STL深入学习】SGI STL空间配置器详解(一)-第一级空间配置器

    一.SGI STL配置器简介 SGI STL的配置器与众不同,它与标准规范不同.如果要在程序中明确使用SGI配置器,那么应该这样写: vector<int,std::alloc> iv; ...

  7. SGI STL allocator

    简单实现是一个allocator C++模板及实现vector_~怎么回事啊~的博客-CSDN博客 SGI STL包含了一级空间配置器和二级空间配置器,其中一级空间配置器allocator采用mall ...

  8. 剖析SGI STL空间配置器(空间配置器的重要性和重要成员及函数)

    剖析SGI STL空间配置器 在我们使用STL容器的时候,模板最后一个参数会有一个默认的allocator作为容器模板的参数,这个参数就是STL的空间配置器.容器的空间配置器见这篇文章:容器空间配置器 ...

  9. 有关SGI STL的alloc

        在STL的使用者层面上,空间配置器一般是隐藏的,使用者不需要知道其具体实现细节即 可进行使用:但是从STL的实现角度来说,由于整个STL的操作对象都存放在容器之内,而容器 需要配置一定的空间来 ...

最新文章

  1. 语言模型自然语言处理[置顶] 哥伦比亚大学 自然语言处理 公开课 授课讲稿 翻译(四)...
  2. CMake常见指令总结
  3. 如果觉得职业看不到头,趁早换工作吧
  4. jpa 测试_使用外星人进行测试:如何使用Arquillian测试JPA类型转换器
  5. 电商系统的积分(即金币)的设计方案
  6. 元胞自动机交通流模型c++_MATLAB——含出入匝道的交织区快速路元胞自动机模型...
  7. centos中mysql操作命令_CentOS系统常用的MySQL操作命令总结
  8. java web 基础知识 流程图
  9. hbuildx微信开发者工具-微信小程序测试
  10. html5 for vs2008插件,Chart 控件 for vs2008的安装
  11. Python与数据库之学员管理系统
  12. OpenGL中矩阵的存储方式
  13. 开心下单助手v1.0免费版
  14. iOS开发 判断输入语言是否是汉语
  15. OU Graphics 建筑后期悬挂植物制作PS教程
  16. java jtextarea 滚动条_Java Swing JTextArea自动添加滚动条
  17. 引爆社群:移动互联网时代的新4C法则
  18. Oracle查询CLOB类型字段的内容:
  19. 1_VBA_POWERSHELL病毒分析
  20. 从0到一开发微信小程序(1)——申请账号并安装开发环境

热门文章

  1. matplotlib画会动的椭圆
  2. YOLOv3 cfg文件详解
  3. ABB机器人编程技巧:双工位预约程序
  4. 全球与中国工业自动化运动控制系统市场现状及未来发展趋势
  5. Jquery图片轮播(连续滚动+突出显示)
  6. java poi 段落行间距,Apache POI Word - 段落( Paragraph)
  7. flappy bird java源码_android高仿flappy bird源码
  8. 用SQLite进行全文检索
  9. HTML文档中注释标记作用,html的注释有什么作用
  10. java哪个软件编程好学吗_java是什么软件好学吗(java编程用哪个软件)