STL源码——RB-Tree insert操作

  看STL源码剖析时,真正的插入函数__insert(base_ptr x, base_ptr y, const value& v)时,发现参数x几乎没什么用,查了一些资料,发现x是在调用另一个insert重载函数时发挥作用的,于是整理了一下insert函数。
  STL关联容器map/multimp,set/multiset,都是使用了红黑树的底层结构。insert有两个重载函数,一个insert(const Value&),一个是insert_unique(iterator, const Value&),后者是带hint的插入。《C++标准程序库》中说道:若被安插元素位置恰好紧贴于提示位置之后,那么时间复杂度就会从“对数”变为“摊还常数”。当hint恰当时,可大大加快速度。
  对于map和set,insert函数会调用rb-tree中的insert_unique版本,对于multimap和multiset,则调用rb-tree中的insert_equal版本。由于insert_equal较insert_unique简单一些,所以这里只分析insert_unique.

template <class Key, class Val, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Val, KeyOfValue, Compare, Alloc>::iterator 
rb_tree<Key, Val, KeyOfValue, Compare, Alloc>::insert_unique(iterator position,
                                                             const Val& v) {
  if (position.node == header->left) // begin()
    if (size() > 0 && key_compare(KeyOfValue()(v), key(position.node)))
      return __insert(position.node, position.node, v);
  // first argument just needs to be non-null 
    else
      return insert_unique(v).first;
  else if (position.node == header) // end()
    if (key_compare(key(rightmost()), KeyOfValue()(v)))
      return __insert(0, rightmost(), v);
    else
      return insert_unique(v).first;
  else {
    iterator before = position;
    --before;
    if (key_compare(key(before.node), KeyOfValue()(v))
        && key_compare(KeyOfValue()(v), key(position.node)))
      if (right(before.node) == 0)
        return __insert(0, before.node, v); 
      else
        return __insert(position.node, position.node, v);
    // first argument just needs to be non-null 
    else
      return insert_unique(v).first;
  }
}

以上代码思路如下:
  

  1. pos为leftmost(提示位置为begin)

    1. v < leftmost:直接插在leftmost的左儿子处即可。此时第一个参数不为空。
    2. 否则直接调用insert_unique无hint版本
  2. pos为header(提示位置为end)

    1. rightmost < v:插到rightmost的右儿子处,即:调用insert(0,rightmost,v)

    2. 否则直接调用insert_unique无hint版本

  3. pos既不是begin,也不是end, before = pos - 1

    1. before < v < pos

      1. before 右子树为空 before是pos左子树中的最大值(before一定没有右儿子),则插入点为before的右儿子处
      2. before有右儿子 pos是before的右子树中最小值(pos一定没有左儿子),则插入点为pos的左儿子处
    2. 否则直接调用insert_unique无hint版本

不带hint的insert_unique函数如下:

// 安插新值;節點鍵值不允許重複,若重複則安插無效。
// 注意,傳回值是個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 所指即安插點之父節點(此時的它必為葉節點)

  iterator j = iterator(y);   // 令迭代器j指向安插點之父節點 y
  if (comp) // 如果離開 while 迴圈時 comp 為真(表示遇「大」,將安插於左側)
    if (j == begin())   // 如果安插點之父節點為最左節點
      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);
}

  以上iterator j的作用为:若待插入的key与某个结点相同(设为p),则在while循环中,某一次x = p后,大于等于向右走,则下一次x = p.right,由于v的值一定小于p的右子树中任何一个值,所以进入p的右子树后,x一定是一直向左走直到节点y(y的左儿子为空)。则y为p的右子树最小值,iterator(p) = iterator(y) - 1,p即为代码中的j。若v与j的值不同,则可以执行插入操作,否则返回j和false。
  实际完成插入的函数为__insert(hint, parent, v),当hint不为0时,直接插在左儿子处,代码如下:

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 是鍵值大小比較準則。應該會是個 function object。
  if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {      //x != 0时,直接插到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(z, header->parent);   // 參數一為新增節點,參數二為 root
  ++node_count;         // 節點數累加
  return iterator(z);   // 傳回一個迭代器,指向新增節點
}

你可能感兴趣的:(源码,STL)