1. 程式人生 > 實用技巧 >deque容器的insert函式

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;
}