SGISTL源码探究-STL中的红黑树(下)

前言

在上一小节中,我们针对SGISTL中的红黑树的分析完成了一半,接下来的各种操作才是重点的部分。通过以下分析可以了解到红黑树是如何保持平衡的。(STL中实现红黑树定义的重载版本函数太多,我舍去了一部分定义,直接对其声明进行分析,不然篇幅太长)

红黑树的常用操作

clear

上一小节中,析构函数调用了clear,它的实现如下

  void clear() {
    if (node_count != 0) {
      //调用了__erase
      __erase(root());
      //将红黑树恢复到初始状态
      leftmost() = header;
      root() = 0;
      rightmost() = header;
      node_count = 0;
    }
  }      
重载操作符==

判断两个红黑树是否相等的条件是两者大小相等,

template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
inline bool operator==(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x,
                       const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& y) {
  return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
}
重载操作符=
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x) {
  if (this != &x) {
                                // Note that Key may be a constant type.
    clear();
    node_count = 0;
    key_compare = x.key_compare;      
    //根结点为null,这就很简单了,直接设置header为初始状态即可
    if (x.root() == 0) {
      root() = 0;
      leftmost() = header;
      rightmost() = header;
    }
    else {
      //否则调用__copy函数进行复制
      root() = __copy(x.root(), header);
      //然后设置header及node_count
      leftmost() = minimum(root());
      rightmost() = maximum(root());
      node_count = x.node_count;
    }
  }
  return *this;
}
插入操作
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;

  //y为header或x不为空或者要插入的值的key与y不重复
  if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
    //创建并初始化值为v的节点
    z = create_node(v);
    //将header的左孩子设置为z
    left(y) = z;                // also makes leftmost() = z when y == header
    if (y == header) {
      //若y为header,将根结点设置为z
      //并将header的右孩子设置为z
      root() = z;
      rightmost() = z;
    }
    else if (y == leftmost())
      //若y为最小节点,则进行调整
      //让leftmost()永远指向最左节点
      leftmost() = z;           // maintain leftmost() pointing to min node
  }
  else {
    //否则创建值为v的节点
    z = create_node(v);
    //将y的右孩子设置为z
    right(y) = z;
    //维护rightmost
    if (y == rightmost())
      rightmost() = z;          // maintain rightmost() pointing to max node
  }
  //设置新节点的父节点、左孩子节点、右孩子节点
  parent(z) = y;
  left(z) = 0;
  right(z) = 0;
  //新节点的颜色由__rb_tree_rebalance函数设置并进行调整
  __rb_tree_rebalance(z, header->parent);
  //节点数加1
  ++node_count;
  //返回迭代器指向新增节点
  return iterator(z);
}
//插入新值:节点的键值允许重复
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);
}
/* 插入新值,节点的key不允许重复,若重复则插入无效
 * 返回值为pair,第一个元素指向新增节点,第二个元素表示是否插入成功
 */
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));
    x = comp ? left(x) : right(x);
  }
  //令迭代器指向插入点的父节点
  iterator j = iterator(y);
  //若comp为true,则代表应该插入左侧   
  if (comp)
    //如果插入点的父节点为最小值节点
    if (j == begin())     
      return pair<iterator,bool>(__insert(x, y, v), true);
    else
      --j;
  //新键值在红黑树中不重复,则执行插入操作
  if (key_compare(key(j.node), KeyOfValue()(v)))
    return pair<iterator,bool>(__insert(x, y, v), true);
  //返回flase,插入失败
  return pair<iterator,bool>(j, false);
}
删除元素
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
inline void
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::erase(it erator position) {
  //进行平衡性的调整
  link_type y = (link_type) __rb_tree_rebalance_for_erase(position.node,
                                                          header->parent,
                                                          header->left,
                                                          header->right);

  //删除节点并将node_count-1
  destroy_node(y);
  --node_count;
}
//递归删除x为根的所有节点
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
void rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::__erase(link_type x) {
                                // erase without rebalancing
  while (x != 0) {
    __erase(right(x));
    link_type y = left(x);
    destroy_node(x);
    x = y;
  }
}
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
void rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::erase(const Key* first,
                                                            const Key* last) {
  while (first != last) erase(*first++);
}
复制操作
template <class K, class V, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<K, V, KeyOfValue, Compare, Alloc>::link_type
rb_tree<K, V, KeyOfValue, Compare, Alloc>::__copy(link_type x, link_type p) {
                                // structural copy.  x and p must be non-null.
  //复制x结点
  link_type top = clone_node(x);
  //x的父节点
  top->parent = p;

  __STL_TRY {
    //存在右子树,则先到最右端
    if (x->right)
      top->right = __copy(right(x), top);
    //对左子树进行拷贝
    p = top;
    x = left(x);

    while (x != 0) {
      //拷贝x
      link_type y = clone_node(x);
      //设置x的父节点的左节点为y
      p->left = y;
      //设置y的父节点为p
      y->parent = p;
      //对右子树进行复制
      if (x->right)
        y->right = __copy(right(x), y);
      p = y;
      x = left(x);
    }
  }
  __STL_UNWIND(__erase(top));

  return top;
}
查找操作
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>::find(const Key& k) {
  link_type y = header;        // Last node which is not less than k.
  link_type x = root();        // Current node.

  while (x != 0)
    //x键值大于k,则向右走
    if (!key_compare(key(x), k))
      y = x, x = left(x);
    else
    //x键值小于k,则向左走
      x = right(x);

  iterator j = iterator(y);   
  return (j == end() || key_compare(k, key(j.node))) ? end() : j;
}
平衡性的调整

这里只列出最基本的旋转操作。至于插入或者删除时进行的平衡操作建议参考其他资料,因为会分的情况众多,而我们主要的目的是了解STL中红黑树的具体实现。

//左旋
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{
  /* 将x作为旋转点
   * y为旋转点的右子节点
   */
  __rb_tree_node_base* y = x->right;
  x->right = y->left;
  if (y->left !=0)
    //将左子节点的父节点设置为x
    y->left->parent = x;
  y->parent = x->parent;

  //将x的位置替换成y
  if (x == root)
    root = y;
  else if (x == x->parent->left)
    x->parent->left = y;
  else
    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为旋转点
   * y为旋转点的左子节点
  __rb_tree_node_base* y = x->left;
  x->left = y->right;
  if (y->right != 0)
    //将右子节点的父节点设置为x
    y->right->parent = x;
  y->parent = x->parent;

  //y替换x
  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;
}

小结

本小节中,我们将STL中红黑树剩余的部分进行了分析,由于平衡性的调整方面分的情况太多,需要另写一篇详细的博文才能完全理解,所以在这里就不进行讨论了。
在下一小节中,我们将分析map容器的实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值