zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    [LintCode] Longest Substring Without Repeating Characters
    [LeetCode] 416. Partition Equal Subset Sum 相同子集和分割
    [LintCode] Reverse Linked List 倒置链表
    [LintCode] Median of Two Sorted Arrays 两个有序数组的中位数
    [LeetCode] 415. Add Strings 字符串相加
    [LintCode] Longest Consecutive Sequence 求最长连续序列
    [LeetCode] 411. Minimum Unique Word Abbreviation 最短的独一无二的单词缩写
    [LeetCode] 410. Split Array Largest Sum 分割数组的最大值
    [LeetCode] Longest Palindrome 最长回文串
    [LeetCode] Valid Word Abbreviation 验证单词缩写
  • 原文地址:https://www.cnblogs.com/Cxiangyang/p/13922420.html
Copyright © 2011-2022 走看看