天天看點

STL序列式容器之deque

deque概述

vector是單向開口的連續線性空間,deque則是一種雙向開口的連續線性空間。所謂雙向開口,意思是可以在頭尾兩端分别做元素的插入和删除操作。vector當然也可以在頭尾兩端分别做元素的插入删除操作(從技術上說),但是其頭部操作效率極差而無法被接受。

STL序列式容器之deque

deque和vector的最大差異,一是在于deque允許于常數時間内對起頭端進元素的插入或移除操作,二在于deque沒有所謂容量(capacity)觀念,因為它是動态地以分段連續空間組合而成,随時可以增加一段新的空間并連接配接起來。換言之,如vector那樣“因舊空間不足而重新配置一塊更大空間,然後複制元素,再釋放舊空間”這樣的事情在deque是不會發生的。也是以,deque沒有必要提供所謂的空間保留(reserve)功能。

雖然deque也提供Ramdon Access Iterator,但它的疊代器并不是普通指針,其複雜度和vector不可以道理計,是以也影響了各個運算層面。是以,除非必要,我們盡可能選擇使用vector而非deque。對deque進行的排序操作,為了最高效率,可将deque先完整複制到一個vector身上,将vector排序後,在複制回deque。

deque的中控器

deque是連續的空間(至少邏輯上看),連續的線性空間總令我們聯想到array或vector。array無法成長,vector雖可成長,卻隻能向尾部成長,而且所謂成長原是個假象,事實上a.另尋更大的空間,b.将原資料複制過去,c.釋放原空間三部曲。如果不是vector每次配置空間時都有留下一些餘裕,其成長假象帶來的代價是非常高昂的。

deque是由一段一段的定量連續空間構成。一旦有必要在deque的前端或尾端增加新空間,便配置一端定量連續空間,串接在整個deque的頭端或尾端,deque的最大任務,便是在這些分段的定量連續空間上,維護其整體連續的假象。并提供随機存取的接口。避開了“重新配置、複制、釋放”的輪回,代價是複雜的疊代器架構。

受到分段連續線性空間的字面影響,我們可能以為deque的實作複雜度和vector相比雖不中也不遠,其實不然。因為分段連續線性空間必須要有中央控制,而為了維持整體連續的假象,資料結構的設計及疊代器前進後退等操作都較為複雜和繁瑣。deque的實作代碼分量遠比vector或list都多得多。

deque采用一塊所謂的map(這裡并不是map容器)作為主要,是一小塊連續空間,其中每個元素(此處稱為一個節點,node)都是指針,指向另一段較大的連續線性空間,稱為緩沖區。緩沖區才是deque的儲存空間主體。SGI STL允許指定緩沖區的大小,預設值為0,表示将使用512 bytes 緩沖區。

deque部分源代碼

template<class T,class Alloc=alloc, size_t BufSiz=0>
class dedue
{
public:
     typedef T value_type;
     typedef value_type* pointer;
     .......
protected:
//元素的指針的指針
      typedef pointer* map_pointer;//二級指針
      map_pointer map;//指向map,map是塊連續空間,每一個元素都是一個指針(節點),指向一塊緩沖區
      size_type map_size;//map内可容納的指針
      ........
}
           
STL序列式容器之deque

map和node-buffer(節點和緩沖區)的關系

deque的疊代器

deque是分段連續空間,維持其:“整體連續”假象的任務,落在疊代器傳遞operator++和operator–兩個運算子身上。

deque疊代器必須能夠指出分段連續空間(緩沖區)在哪裡,其次它必須判斷自己是否已經處于其所在緩沖區的邊緣,如果是,一旦前進或者後退時就必須跳躍至下一個或上一個緩沖區,為了能夠正确跳躍,deque必須随時掌握管控中心(map)。

template<class T, class Ref, class Ptr, size_t BufSiz>
struct _deque_iterator
{
      typedef _deque_itertaor<T ,T&,T*,BufSiz>   iterator;
      typedef _deque_itertaor<T ,const T&,const T*,BufSiz>   const_iterator;
      static size_t buffer_size() {return _deque_buf_size(BufSiz,sizeof(T));}
      //未繼承 std::iterator, 是以必須自行撰寫五個必要的疊代器相應型别
      typedef random_access_iterator_tag iterator_category;//(1)
      typedef T value_typel;//(2)
      typedef Ptr pointer;//(3)
      typedef Ref reference;//(4)
      typedef size_t size_type;
      typedef ptrdiff_t difference_type;//(5)
      typedef T** map_pointer;
      typedef _deque_iterator self;
      //保持與容器的聯接
      T* cur;//此疊代器所指之緩沖區的現行元素
      T* first;//此疊代器所指之緩沖區的頭
      T* last;//此疊代器所指之緩沖區的尾(包含備用空間)
      map_pointer node;//指向管控中心
      ......
}
           

其中用來決定緩沖區的大小的函數buff_size(),調用_deque_buf_size(),後者是一個全局函數,定義如下:

//如果n不為0,傳回n,表示buffer size有使用者自定義

//如果n為0,表示buffer size使用預設值,那麼如果sz(元素大小,sizeof(value_type))小于512,傳回512/sz;如果sz不小于512,傳回1

inline size_t  _deque_buf_size(size_t n,size_t sz)
{
     return n!=0?n:(sz<512? size_t(512/sz):size_t(1));
}
           
STL序列式容器之deque

deque的中控器、緩沖區、疊代器的互相關系

deque的構造圖

STL序列式容器之deque
STL序列式容器之deque
STL序列式容器之deque
STL序列式容器之deque

deque的元素操作

STL序列式容器之deque