zoukankan      html  css  js  c++  java
  • 红黑树(RB-Tree)

    红黑树性质:

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

     2、根节点为黑色

    3、节点为红色,其子节点必须为黑色(新增节点之父必须为黑)

    4 、任一节点至NULL(树尾端)的任何路径,所含的黑节点必须相同。(新增节点必须为红)

    RB-Tree的设计也采用了两层架构,以下是节点设计:

    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的迭代器属于双向迭代器,其中迭代器的前进及后退操作是调用了基层迭代器increment(),decrement(),如下是基层迭代器:

    //迭代器基类,类型为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;  
      
      //下面只是为了实现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;  
        }  
      }  
    };  

    本来只有root节点,但处理时不方便,每到边界处还得再处理,所以为根节点增加一个父节点header,使header和root互为对方的父节点。

    下面是RB-Tree的正规迭代器

    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;  
      }  
    };  

    RB-Tree的insert_unique()和insert_equal()是两种主要的插入操作

    // 安插新值;允许键值重复。返回新插入节点的迭代器  
    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_equal(const Value& v)  
    {  
      link_type y = header;  
      link_type x = root();    
      while (x != 0) {      // 从根节点开始,向下寻找适当安插位置  
        y = x;  
        x = key_compare(KeyOfValue()(v), key(x)) ? left(x) : right(x);  
      }  
      return __insert(x, y, v);  
    }  
      
    /* 
    不允许键值重复,否则安插无效。 
    返回值是个pair,第一个元素是个RB-tree迭代器,指向新增节点。 
    第二个元素表示安插是否成功。 
    */  
    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 ? left(x) : right(x);  // 遇「大」往左,遇「小于或等于」往右  
      }  
      //离开while循环之后,y所指即为安插点的父节点,x必为叶子节点  
      
      iterator j = iterator(y);   // 令迭代器j指向安插点之父节点 y  
      if (comp) //如果离开while循环时comp为真,表示 父节点键值>v ,将安插在左孩子处  
        if (j == begin())   // 如果j是最左节点  
          return pair<iterator,bool>(__insert(x, y, v), true);  
          // 以上,x 为安插点,y 为安插点之父节点,v 为新值。  
        else    // 否则(安插点之父节点不是最左节点)  
          --j;  // 调整 j,回头准备测试...  
      if (key_compare(key(j.node), KeyOfValue()(v)))      
        // 小于新值(表示遇「小」,将安插于右侧)  
        return pair<iterator,bool>(__insert(x, y, v), true);  
      
      //若运行到这里,表示键值有重复,不应该插入  
      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;  
      
      //key_compare是键值得比较准则,是个函数或函数指针  
      if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {  
        z = create_node(v);  // 产生一个新节点  
        left(y) = z;          // 这使得当y为header时,leftmost()=z  
        if (y == header) {  
          root() = z;  
          rightmost() = z;  
        }  
        else if (y == leftmost())   // 如果y为最左节点  
          leftmost() = z;               // 维护leftmost(),使它永远指向最左节点  
      }  
      else {  
        z = create_node(v);  
        right(y) = z;               // 令新节点成为安插点之父节点y的右孩子  
        if (y == rightmost())  
          rightmost() = z;              // 维护rightmost(),使它永远指向最右节点  
      }  
      parent(z) = y;        // 设定新节点的父节点  
      left(z) = 0;      // 设定新孩子节点的左孩子  
      right(z) = 0;         // 设定新孩子节点的右孩子  
                              // 新节点的颜色将在 __rb_tree_rebalance() 设定并调整  
      __rb_tree_rebalance(z, header->parent);    // 参数一为新增节点,参数二为root  
      ++node_count;     // 节点数增加  
      return iterator(z);   // 返回迭代器,指向新增节点  
    }  

    作为平衡树,最重要的是调节保持平衡,如下几个函数:

    //左旋转  
    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对其父节点的关系完全接收过来)  
      if (x == root)                    // x 为根节点  
        root = y;  
      else if (x == x->parent->left)  // x 为父节点的左孩子  
        x->parent->left = y;  
      else                          // 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)  
    {  
      // x 为旋转点  
      __rb_tree_node_base* y = x->left;  // y x的左孩子  
      x->left = y->right;  
      if (y->right != 0)  
        y->right->parent = x;     // 別忘了回马枪设置父节点  
      y->parent = x->parent;  
      
      // 令 y 完全顶替 x 的地位(必须将x对其父节点的关系完全接收过来)  
      if (x == root)                    // x 为根节点  
        root = y;  
      else if (x == x->parent->right) // x 为父节点的右孩子  
        x->parent->right = y;  
      else                          // x 为父节点的左孩子  
        x->parent->left = y;  
      y->right = x;  
      x->parent = y;  
    }  
      
      
    //重新令RB-tree平衡(改变颜色和旋转)参数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 为伯父节点  
          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 {    // 无伯父节点或伯父节点为黑色(NULL就是黑色)  
            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为伯父节点  
          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 {    // 无伯父节点或伯父节点为黑色(NULL就是黑色)  
            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); // 第一个参数做旋转  
          }  
        }  
      } // while 結束  
      root->color = __rb_tree_black; // 根节点永远为黑色  
    }  
    //删除结点z  
    inline __rb_tree_node_base*  
    __rb_tree_rebalance_for_erase(__rb_tree_node_base* z,  
                                  __rb_tree_node_base*& root,  
                                  __rb_tree_node_base*& leftmost,  
                                  __rb_tree_node_base*& rightmost)  
    {  
      __rb_tree_node_base* y = z;  
      __rb_tree_node_base* x = 0;  
      __rb_tree_node_base* x_parent = 0;  
      if (y->left == 0)             // z has at most one non-null child. y == z.  
        x = y->right;               // x might be null.  
      else  
        if (y->right == 0)          // z has exactly one non-null child.  y == z.  
          x = y->left;              // x is not null.  
        else {                      // z has two non-null children.  Set y to  
          y = y->right;             //   z's successor.  x might be null.  
          while (y->left != 0)  
            y = y->left;  
          x = y->right;  
        }  
      if (y != z) {                 // relink y in place of z.  y is z's successor  
        z->left->parent = y;   
        y->left = z->left;  
        if (y != z->right) {  
          x_parent = y->parent;  
          if (x) x->parent = y->parent;  
          y->parent->left = x;      // y must be a left child  
          y->right = z->right;  
          z->right->parent = y;  
        }  
        else  
          x_parent = y;    
        if (root == z)  
          root = y;  
        else if (z->parent->left == z)  
          z->parent->left = y;  
        else   
          z->parent->right = y;  
        y->parent = z->parent;  
        __STD::swap(y->color, z->color);  
        y = z;  
        // y now points to node to be actually deleted  
      }  
      else {                        // y == z  
        x_parent = y->parent;  
        if (x) x->parent = y->parent;     
        if (root == z)  
          root = x;  
        else   
          if (z->parent->left == z)  
            z->parent->left = x;  
          else  
            z->parent->right = x;  
        if (leftmost == z)   
          if (z->right == 0)        // z->left must be null also  
            leftmost = z->parent;  
        // makes leftmost == header if z == root  
          else  
            leftmost = __rb_tree_node_base::minimum(x);  
        if (rightmost == z)    
          if (z->left == 0)         // z->right must be null also  
            rightmost = z->parent;    
        // makes rightmost == header if z == root  
          else                      // x == z->left  
            rightmost = __rb_tree_node_base::maximum(x);  
      }  
      if (y->color != __rb_tree_red) {   
        while (x != root && (x == 0 || x->color == __rb_tree_black))  
          if (x == x_parent->left) {  
            __rb_tree_node_base* w = x_parent->right;  
            if (w->color == __rb_tree_red) {  
              w->color = __rb_tree_black;  
              x_parent->color = __rb_tree_red;  
              __rb_tree_rotate_left(x_parent, root);  
              w = x_parent->right;  
            }  
            if ((w->left == 0 || w->left->color == __rb_tree_black) &&  
                (w->right == 0 || w->right->color == __rb_tree_black)) {  
              w->color = __rb_tree_red;  
              x = x_parent;  
              x_parent = x_parent->parent;  
            } else {  
              if (w->right == 0 || w->right->color == __rb_tree_black) {  
                if (w->left) w->left->color = __rb_tree_black;  
                w->color = __rb_tree_red;  
                __rb_tree_rotate_right(w, root);  
                w = x_parent->right;  
              }  
              w->color = x_parent->color;  
              x_parent->color = __rb_tree_black;  
              if (w->right) w->right->color = __rb_tree_black;  
              __rb_tree_rotate_left(x_parent, root);  
              break;  
            }  
          } else {                  // same as above, with right <-> left.  
            __rb_tree_node_base* w = x_parent->left;  
            if (w->color == __rb_tree_red) {  
              w->color = __rb_tree_black;  
              x_parent->color = __rb_tree_red;  
              __rb_tree_rotate_right(x_parent, root);  
              w = x_parent->left;  
            }  
            if ((w->right == 0 || w->right->color == __rb_tree_black) &&  
                (w->left == 0 || w->left->color == __rb_tree_black)) {  
              w->color = __rb_tree_red;  
              x = x_parent;  
              x_parent = x_parent->parent;  
            } else {  
              if (w->left == 0 || w->left->color == __rb_tree_black) {  
                if (w->right) w->right->color = __rb_tree_black;  
                w->color = __rb_tree_red;  
                __rb_tree_rotate_left(w, root);  
                w = x_parent->left;  
              }  
              w->color = x_parent->color;  
              x_parent->color = __rb_tree_black;  
              if (w->left) w->left->color = __rb_tree_black;  
              __rb_tree_rotate_right(x_parent, root);  
              break;  
            }  
          }  
        if (x) x->color = __rb_tree_black;  
      }  
      return y;  
    }  
  • 相关阅读:
    26. 60s快速定位服务器性能问题
    27. 性能测试总体流程
    18. Jmeter-取样器二
    17. Jmeter-取样器一
    15. Jmeter-配置元件二
    14. Jmeter-配置元件一
    13. Jmeter-定时器
    git 常用命令
    数据库常用操作
    【CSS】文字超出显示省略号&连续字符换行
  • 原文地址:https://www.cnblogs.com/daocaorenblog/p/5305208.html
Copyright © 2011-2022 走看看