【STL源码剖析】第五章 关联式容器 之 RB-tree(红黑树)

RB-tree

[ 红黑树比AVL树的优势 ]( https://blog.csdn.net/mmshixing/article/details/51692892 )

RB-tree不仅是一个二叉搜索树,而且必须满足一些规则:

  1. 每个节点不是红色就是黑色(图中深色代表黑,浅色代表红)

  2. 根节点为黑色

  3. 如果节点为红,其子节点必须为黑

  4. 任一节点至NULL(树尾端)的任何路径,所含之黑节点数必须相同

根据规则4,新增节点不许为红;根据规则3,新增节点之父节点必须为黑。当新节点根据二叉搜索树的规则到达其插入点,却未能符合上述条件时,就必须调整颜色并旋转树形。

插入节点

在图5-13的RB-tree分别插入3,8,35,75,根据二叉搜索树的规则,这四个新节点落脚处应如图5-14所示,它们破坏了RB-tree的规则,因此必须调整树形,也就是旋转树形并改变节点颜色。

假设新节点为X,其父节点为P,祖父节点为G,伯父节点(父节点的兄弟节点)为S,曾祖父节点为GG

  • 状况1:S为黑且X为外侧插入。对此情况,先对P,G做一次单选转,再更改P,G颜色,即可重新满足红黑树的规则3。

  • 状况2:S为黑且X为内测插入。对此情况,必须现对P,X做一次单选转并更改G,X颜色,再将结果对G做一次单选转,即可再次满足红黑树规则3。

  • 状况3:S为红且X为外侧插入。对此情况,现对P和G做一次单选转,并改变X的颜色。此时如果GG为黑,一切搞定,但如果GG为红,则问题比较大,见状况4。

  • 状况4:S为红且X为外侧插入。对此情况,先对P和G做一次单选转,并改便X的颜色。此时如果GG也为红。害的持续网上做,直到不再有父子连续为红的情况。

一个自上而下的程序

为避免插入节点的情况4,可以用自顶向下的方法:假设新增节点为A,就顺着A的路径,当遇到一个节点X的两个儿子都为红,就将X改为红,两个儿子改为黑。当X的父节点也为红使用情况1或情况2中的方法做调整。

RB-tree的节点设计

RB-tree有红黑二色,并且拥有左右子节点,很容易勾勒出其结构风貌。下面是SGI STL的实现源码。为了有更大的弹性,节点分为两层。

由于RB-tree的各种操作时常需要上溯其父节点,所以特别在数据结构中安排了一个parent指针。

  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的迭代器

SGI将RB-tree迭代器实现分为两层。图5-16是两层节点结构和双层迭代器结构间的关系,其中主要意义是: _ rb_tree_node 继承自 rb_tree_node_base ,rb_tree_iterator继承自_rb_tree_base_iterator。

RB-tree的元素操作

RB-tree提供两种插入操作:insert_unique()和insert_equal(),前者标识被插入节点的键值(key)在整棵树中必须独一无二(因此,如果整棵树中已存在相同的键值,插入操作就不会真正进行),后者标识被插入节点的键值在整棵树中可以重复,因此,无论如何插入都会成功(除非空间不足导致配置失败)。



猜你喜欢

转载自blog.csdn.net/u012940886/article/details/80698758
今日推荐