deque容器的insert函数

deque容器的结构就是多个指针串接起来的多块缓冲区,其中的指针也保存在一块缓冲区中,源码中称其为map(不是容器map),借此实现连续空间的假象,说起来其结构比真正的连续空间vector复杂多了,好处就是不用特意维持一块真正的连续空间(想想如果数据量超级大,当空间满了后需要继续添加元素,就得整个进行内存拷贝,可怕),当需要进行内存移动时,可以减少移动的数据量(后边看insert就知道),借用stl源码剖析的图,deque结构如下,就不打了。

 

 

 实际上进行insert操作,如果不是再首部或者尾部插入都会造成内存拷贝,尤其是当插入的位置在容器中间时,就意味着需要进行一半数据量的内存拷贝,而且相比于vector,deque维持这样的 “连续” 空间需要付出更大的代价,和vector一样,在需要大量使用插入删除的操作场景下,优先考虑其他容器。

deque的insert有多个重载版本,这里就记录源码剖析里的例子,其它的大同小异

  iterator insert(iterator position, const value_type& x) {
    if (position.cur == start.cur) {
      /*插入最前端*/
      push_front(x);
      return start;
    }
    else if (position.cur == finish.cur) {
      /*插入最尾端*/
      push_back(x);
      iterator tmp = finish;
      --tmp;
      return tmp;
    }
    else {
  /*其它位置*/
return insert_aux(position, x); } }

当插入最前端或者最后端是调用push_front或者push_back函数实现。

这两个函数的实现比较简单,这里列出push_front的实现  void push_front(const value_type& t) {

  void push_front(const value_type& t) {
    if (start.cur != start.first) {
      /*第一块缓冲区还有剩余位置*/
      /*构造start.cur的前一个位置*/
      construct(start.cur - 1, t);
      /*start.cur前移一步*/
      --start.cur;
    }
    else
      push_front_aux(t);
  }

// Called only if start.cur == start.first.
//第一个缓冲区已经满了
template <class T, class Alloc, size_t BufSize> void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t) { /*记下value*/ value_type t_copy = t; /*判断是否需要更换map(deque要维持其首尾两边有可用空间)*/ /*想象一下也知道,更换map就是把挂着的给个缓冲区指针复制到另一段空间去,然后更改前后迭代器的指向*/ reserve_map_at_front(); /*首节点前一个位置构造一条新的缓冲区*/ *(start.node - 1) = allocate_node(); __STL_TRY { /*更换首节点位置(start是deque的迭代器,永远指向第一个节点)*/ start.set_node(start.node - 1); /*设置cur为缓冲区最后一个位置(前移了一步)*/ start.cur = start.last - 1; /*新节点构造初值*/ construct(start.cur, t_copy); } # ifdef __STL_USE_EXCEPTIONS catch(...) { /*异常回滚操作*/ start.set_node(start.node + 1); start.cur = start.first; deallocate_node(*(start.node - 1)); throw; } # endif /* __STL_USE_EXCEPTIONS */ }

罗里吧嗦将了一堆,终于到正题了insert_aux(position, x)

这个函数的作用就是向迭代器position指向的位置前插入一个元素x(头插法)

 

template <class T, class Alloc, size_t BufSize>
typename deque<T, Alloc, BufSize>::iterator
deque<T, Alloc, BufSize>::insert_aux(iterator pos, const value_type& x) {
  /*插入点前的元素个数*/
  difference_type index = pos - start;
  /*待插入的value*/
  value_type x_copy = x;
  /*根据插入点前后元素数量决定做前移或者后移操作*/
  /*使得实现少的内存拷贝*/
  if (index < size() / 2) {
    /*插入点前的元素个数较少*/
    /*最前端加一个元素,以此时的front()为初值*/
    push_front(front());
    /*此时的start赋值给front1,记住push_front后start会前移*/
    /*下边四行将形成 start front1 front2从前往后的依次排序*/
    iterator front1 = start;
    ++front1;
    iterator front2 = front1;
    ++front2;
    /*重设pos位置(前移了一个元素位置)*/
    pos = start + index;
    /*用pos1指向原pos的位置*/
    iterator pos1 = pos;
    ++pos1;
    /*将区间[front2,pos1)整个区间前移一步*/
    copy(front2, pos1, front1);
  }
  else {
    /*插入点前的元素较多,所以选择插入点后的元素整体后移一步*/
    push_back(back());
    iterator back1 = finish;
    --back1;
    iterator back2 = back1;
    --back2;
    pos = start + index;
    /*逆向拷贝(后移)*/
    copy_backward(pos, back2, back1);
  }
  /*安插点设置值*/
  /*空出来的这个位置赋值为value*/
  *pos = x_copy;
  return pos;
}

 

posted @ 2020-11-04 10:01  乐swap火  阅读(675)  评论(0编辑  收藏  举报