STL RB-tree

一.RB-tree概述

       红黑树是二叉平衡搜索树的一种,它确保了搜索时间的复杂度为O(logn),且其维护平衡所付出的代价小于AVL树,因为AVL树要求左右子树高度差最多为1,而红黑树通过一系列规则保证左右子树的高度差不超过2倍。

       红黑树的规则如下:

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

       2)根节点为黑色

       3)如果节点为红,则其子节点必须为黑,这也就要求新增节点的父节点必须为黑,否则破坏平衡进行调节。

       4)从任一节点起至NULL节点的任何路径,所含黑节点数必须相同。这也就要求每次新增的节点必为红。

       红黑树便是通过规则3和规则4保证了左右子树的高度差不超过2倍,因为从任一节点到NULL节点的路径上黑节点数是相同的,设为n个,而红节点不可两两相连,因此最多是红黑相间,所以最多为n个,所以左右子树间的差值至多为2n / n = 2,即不超过两倍。

 

二.RB-tree的插入规则

       新增节点必为红,而当新增节点的父节点也为红色时便违反了规则3,此时需要进行调整。红黑树的调整规则大的分类上可分为两种:在祖父节点的左子树中插入和在祖父节点的右子树中插入,其两者之间只是在某种情况下旋转的顺序反一下而已。每一种中又包含:伯父节点为黑和伯父节点为红。我们就以在祖父节点的左子树中插入为例

2.1 伯父节点为红

       将父节点与伯父节点变黑,并将祖父节点变红,接着观察祖父节点与增祖父节点的关系是否违反规则,若违反则继续上推。若祖父系节点是根节点,则将祖父节点在变黑,之后退出。

 

【注】:祖父节点必为黑,因为若祖父节点为宏则父节点不可能为红,新增x也不会破坏规则了

2.2 伯父节点为黑

      伯父节点为黑时又分为两种情况::新增节点为外侧插入和新增节点为内侧插入

1) 新增节点为外侧插入

       此时先将父节点变黑,祖父节点变红,再以祖父节点为旋转点进行右旋:

 

2) 新增节点为内侧插入

   先以父节点进行左旋(即旋转为了外侧插入的样子,只要记住了外侧插入就记住了内侧插入),再将新增节点变为黑,祖父节点变为红,最后以祖父节点为旋转点进行右旋

 

STL中关于旋转的代码如下:

// __x为新增节点,__root为根节点
inline void 
_Rb_tree_rebalance(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root)
{
  __x->_M_color = _S_rb_tree_red; // 新增节点的颜色必为红
  while (__x != __root && __x->_M_parent->_M_color == _S_rb_tree_red) { // 若父节点非根节点,且父节点为红(说明违反规则)
    if (__x->_M_parent == __x->_M_parent->_M_parent->_M_left) { // 若插入节点的父节点是祖父节点的左节点
      _Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_right;
      // - 若伯父节点为红节点则将父节点与伯父节点变黑,将增祖父节点变红。
      // 再继续判断祖父节点与增祖父节点的关系,直至规则
      //
      // - 若伯父节点为黑节点且为内测插入则先以父节点为旋转点进行左旋
      // 再将父节点变为黑,祖父节点变为红,最后以祖父节点为旋转点进行右旋
      // 若不是内测插入则无需进行左旋步骤
      if (__y && __y->_M_color == _S_rb_tree_red) { // 若伯父节点为红节点
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __y->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; // 当将某一子树的根节点由黑变为红时,为了保证黑节点的数量平等,必将其左右子节点变为黑
        __x = __x->_M_parent->_M_parent; // 接着令__x指向伯父节点,继续上推。因为祖父节点变红后,增祖父节点可能也为红,需要继续调整
      }
      else {// 若伯父节点为黑节点(空也算黑节点)
        if (__x == __x->_M_parent->_M_right) { // 若__x为内侧插入,即为父节点的右节点
          __x = __x->_M_parent;
          _Rb_tree_rotate_left(__x, __root); // 以父节点为旋转点进行左旋
        }
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
        _Rb_tree_rotate_right(__x->_M_parent->_M_parent, __root); // 以祖父节点为旋转点进行右旋,以保证黑节点的平衡
      }
    }
    else { // 若插入节点的父节点是祖父节点的右节点(即处理时旋转顺序调换一下)
      _Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_left;
      if (__y && __y->_M_color == _S_rb_tree_red) {
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __y->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
        __x = __x->_M_parent->_M_parent;
      }
      else {
        if (__x == __x->_M_parent->_M_left) {
          __x = __x->_M_parent;
          _Rb_tree_rotate_right(__x, __root);
        }
        __x->_M_parent->_M_color = _S_rb_tree_black;
        __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red;
        _Rb_tree_rotate_left(__x->_M_parent->_M_parent, __root);
      }
    }
  }
  __root->_M_color = _S_rb_tree_black; // 将根节点变为黑以满足规则。
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值