STL容器 deque實現

2021-08-19 05:59:09 字數 2688 閱讀 4259

vector是單向開口的連續線性空間,deque則是一種雙向開口的連續線性空間,可以在頭尾兩端分別做元素的插入和刪除操作。vector雖然從技術上也可以實現對頭尾兩端進行操作,但由於vector的底層實現特點的原因,其頭部操作效率奇差,故stl沒有為vector實現這一功能。

deque和vector的最大差異,一在於deque允許於常數時間內對頭部進行插入和刪除操作,二在於deque是動態地以分段連續空間組合而成,隨時可以增加一段新的空間並與已有空間鏈結起來,因此像vector那樣「因舊空間不足而重新配置一塊更大的空間,複製元素過去再釋放舊空間」這樣的事情在deque是不會發生的。

雖然deque也提供ramdon access iterator,但它的迭代器並不是普通指標,其複雜度遠比vector的迭代器要高得多。迭代器的實現差異影響到各種演算法的效率,因此除非必要,應盡可能使用vector而非deque。某些操作(例如排序)可以將deque中的元素先完整複製到乙個vector中,在vector中操作後再複製回deque。

為了實現邏輯上的連續線性空間(實際上是分段的連續線性空間),deque必須定義相應的資料結構來儲存和管理這些分段的線性空間。如下圖所示:

首先應該用另乙個連續空間來儲存這些分段連續空間的位置,也即這個空間用來儲存每一段存放元素的空間的起始位置(指標),stl將這個資料結構命名為map,它實際上相當於乙個指標陣列,它的每個元素都指向另一段連續線性空間,稱為緩衝區。緩衝區才是deque的儲存空間主體,我們用deque來儲存的資料都放在這一段段緩衝區中。sgi stl允許我們制定緩衝區的大小,預設值0表示將使用512bytes緩衝區。

template class deque
其次,deque的迭代器也必須做特殊實現。由上圖可推斷出,deque的迭代器必須知道分段連續空間(即緩衝區)在**。然後,為了實現迭代器移動,它必須能判斷自己是否已經處於其所在緩衝區的邊緣,如果是,移動時就需要跳躍至下乙個或上乙個緩衝區。為了能夠正確跳躍,deque必須隨時掌握中控器(map)。迭代器由4個資料組成,node指向中控器map,first指向*node指向的緩衝區的首元素,last指向尾元素,cur則指向緩衝區中的現行(當前訪問位置)元素。

deque的迭代器設計如下:

template struct __deque_iterator 

//未繼承std::iterator,必須自行定義5個必要的迭代器相應型別

typedef random_access_iterator_tag iterator_category;

typedef ptr pointer;

typedef ref reference;

typedef size_t size_type;

typedef ptrdiff_t defference_type;

typedef t** map_pointer;

typedef __deque_iterator self;

//保持與容器的聯結

t* cur;

t* first;

t* last;

map_pointer node;

...}

用來決定緩衝區大小的函式buff_size()呼叫__deque_buf_size(),後者是全域性函式,定義如下:

inline size_t __deque_buf_size(size_t n, size_t sz)
前文已經提到deque的迭代器比較特殊,它需要判斷邊界以進行「跳躍」緩衝區的操作,因此它的各種加減運算都需要對指標運算子進行過載。跳躍緩衝區的操作由set_node()函式來實現:

void set_node(map_pointer new_node)

以迭代器跳躍n個距離的原始碼為例:

self& operator+=(defference_type n)

return *this;

}上述**中對負數的處理是很有用的,因為當我們定義相反的運算子時,只需要將n值取反即可;

self& operator-=(difference_type n)

deque除了維護乙個指向map的指標外,也維護start,finish兩個迭代器,分別指向第一緩衝區的第乙個元素和最後緩衝區的最後乙個元素的下乙個迭代器(尾後迭代器)。這是為了動態增長map的大小而設計的,其增長的底層實現方式與vector一樣都是構造一塊更大的空間,將舊空間的元素複製過去,再銷毀舊空間。但由於維持deque的特點以及map的複雜性,其**實現上要考慮的因素更多。

deque的定義如下:

template

class deque

原始碼實現中,當deque的map不夠時,會構造乙個至少大小是8,至多是「所需緩衝區加2」(前後各預留乙個,方便擴充),將元素複製過去。不同的是,由於deque是可以雙向增長的,因此舊空間中的元素都放置在新空間的中間位置。複製後將start和finish兩個迭代器內的指標都更新好,再構造緩衝區,這樣就完成了乙個map的增長過程。

本文摘自《stl原始碼剖析》,有改動

STL通用容器之 deque 容器

1.5deque容器 deque容器為乙個給定型別的元素進行線性處理,就如向量,它能夠快速地隨機進入任乙個元素,並且能夠高效地 入和刪除容器的尾部元素。但它與vector不同,deque能支援高效插入和刪除容器的頭部元素,也叫做雙端佇列.1 建構函式 deque 建立乙個空deque deque i...

stl之序列容器 deque

相比於vector,deque是一種雙向開口的連續線性空間,可以在頭尾兩端分別做元素的插入和刪除操作。這也決定了其更賦值的容器結構。deque內部維護了start和finish 節點,用於雙端的插入和刪除 map,一塊連續空間,其每個元素都是個指標,指向乙個節點。其指向的節點中有四個元素 cur f...

(五)STL序列容器(deque)

採用的是連續的線性空間 deque 儲存的空間是由一段一段等長的連續空間構成,各段空間之間並不一定是連續的,可以位於在記憶體的不同 為管理這些連續的空間,deque容器用陣列儲存著各個連續空間的位址,即陣列中儲存的都是指標,由於 deque 容器底層將序列中的元素分別儲存到了不同段的連續空間中,因此...