標籤:sig 注意 建立 設定 迴圈 反轉 訪問 AC 範圍
容器是一種容納特定類型對象的集合。C++的容器可以分為兩類:順序容器和關聯容器。順序容器的元素排列和元素值大小無關,而是由元素添加到容器中的次序決定的。標準庫定義了三種順序容器的類型:vector、list和deque(雙端隊列)。此外,標準庫還提供了三種容器適配器:stack、queue和prioroty_queue類型。適配器是根據原始的容器類型所提供的操作,通過定義新的操作介面,來適應基礎的容器類型。見下表
順序容器vector 支援快速隨機訪問list 支援快速插入/刪除deque 雙端隊列順序容器適配器stack 後進先出(LIFO)棧queue 先進先出(FIFO)隊列priority_queue 有優先順序管理的隊列
一.定義和初始化
定義一個容器類型的對象之前,必須包含相關的標頭檔。如下:
#include<list>#include<vector>#include<deque>
所有容器都定義了預設建構函式,可以用預設建構函式來初始化一個空的容器物件,如下:
list<int> ilist;
此外,容器還有幾種建構函式,可以用來初始化容器物件,如下:
C<T> c 建立一個名為c的空容器。C是容器名,T是元素類型。適用於所有容器C c(c2) 建立容器c2的副本c。兩者必須是相同類型的容器和元素。適用於所有容器C c(b,e) 建立c,其元素是迭代器b和e標記範圍內元素的副本。適用於所有容器C c(n,t) 用n個值為t的元素建立c,其中t必須是容器類型C的元素類型的值或者是可以轉化為該類型的值。只適用於順序容器C c(n) 建立n個初始化元素的容器c。只適用於順序容器
值得注意到是,接受容器大小做形參的建構函式只適用於順序容器,不適用於關聯容器。由於指標就是迭代器,因此我們還可以通過使用內建數組中的一對指標初始化容器:
char *words[]={"Hi","How","Are","You“};size_t words_size=sizeof(words)/sizeof(char *); // 使用整個數組初始化wordslist<string> words2(words,words+words_size);
前面我們說過,容器是儲存某中類型元素的集合,所以可以定義元素是容器類型的容器。例如,可以定義vector類型的容器ivec,其元素為string類型的vector。但是注意,在指定容器元素為容器類型時,必須使用如下空格:
vector< vector<string> > ivec; //合法。在兩個>之間有空格vector<vector<string>> ivec; //錯誤。在兩個>之間沒有空格,>>會導致歧義
二.常用操作
順序容器內建了一些有用的操作:(1)在容器中添加元素;(2)在容器中刪除元素;(3)設定容器大小;(4)(如果有的話)擷取容器內的第一個和最後一個元素。
1.begin和end
begin和end操作產生指向容器內第一個元素和最後一個元素的下一位置的迭代器。此外還有逆序迭代器(逆序迭代器從後向前遍曆容器,並反轉了某些相關的迭代器操作)rbegin和rend。如下:
c.begin() 返回一個迭代器,它指向容器c的第一個元素c.end() 返回一個迭代器,它指向容器c的最後一個元素的下一個位置c.rbegin() 返回一個逆序迭代器,它指向容器c的最後一個元素c.rend() 返回一個逆序迭代器,它指向容器c的第一個元素的前一個位置
2.容器添加元素操作
下表為在順序表中添加元素的操作。注意其中的適用範圍和傳回型別。
c.push_back() 在容器c的尾部添加值為t的元素。返回void類型c.push_front(t) 在容器c的前端添加值為t的元素。返回void類型。只適用於list和deque容器類型c.insert(p,t) 在迭代器p所指向的元素前面插入值為t的新元素。返回指向新添加元素的迭代器c.insert(p,n,t) 在迭代器p所指向的元素前面插入n個值為t的新元素。返回void類型c.insert(p,b,e) 在迭代器p所指向的元素前面插入由迭代器b和e標記的範圍內的元素。返回void類型
其中push_front只適用於list和deque容器類型,這個操作實現在首部插入新元素的功能。
//用push_front在容器尾部依次添加0,1,2,3list<int> ilist;for(size_t i=0;i!=4;++i) ilist.push_front(i);//ilist內元素序列為:3,2,1,0
需要注意的是,任何insert或push操作都可以導致迭代器失效。所以在編寫迴圈將元素插入到vector和deque容器中時,程式必須確保迭代器在每次迴圈後都的到更新。
vector<string> ivec;vector<string>::iterator iter=ivec.begin();while(cin>>word) iter=ivec.insert(iter,word); //效果和push_back一樣//以下是錯誤的,因為此時iter已經失效vector<string> ivec;vector<string>::iterator iter=ivec.begin();while(cin>>word) ivec.insert(iter,word); //錯誤,經過一輪的insert後iter即失效,不能再調用
3.容器大小的操作
所有容器都提供以下與容器大小相關的操作。注意resize操作可能會使迭代器失效。
c.size() 返回容器c中元素的個數。傳回型別為c::size_typec.max_size() 返回容器c可以容納的最多的元素個數.傳回型別為c::size_typec.empty() 返回標記容器大小是否為0的布爾值c.resize(n) 調整容器c的長度大小,使其能容納n個元素。如果n<c.size(),則刪除多出來的元素c.resize(n,t) 調整容器c的大小,使其能容納n個元素。所有新添加的元素值為t
在vector和deque容器上做resize操作有可能會使其所有迭代器都失效。對於所有的容器類型,如果resize操作壓縮了容器,則指向已刪除的元素的迭代器會失效。
4.訪問容器元素的操作
以下為訪問容器元素的操作。注意·使用越界的下標,或調用空容器的front或back函數,都會導致程式出現嚴重的錯誤。
c.back() 返回容器c的最後一個元素的引用。如果c為空白,則該操作未定義c.front() 返回容器c的第一個元素的引用。如果c為空白,則該操作未定義c[n] 返回下標為n的元素的引用。如果n<0或n>=c.size(),則該操作未定義。只適用於vector和deque容器c.at(n) 返回下標為n的元素的引用。如果下標越界,則該操作未定義。只適用於vector和deque容器
5.刪除容器元素的操作
以下為刪除容器元素的操作。刪除操作會使一些迭代器失效,需要特別注意。下表第一個操作在刪除元素前,必須保證迭代器不是指向end的迭代器。
c.erase(p) 刪除迭代器p指向的元素。返回一個迭代器,它指向被刪除元素後面的元素。如果p指向容器內最後一個元素,則返回的迭代器指向容器的超出末端的下一位置。
如果p本身就是超出容器末端的下一個位置,則該函數未定義c.erase(b,e) 刪除迭代器b和e所標記的範圍內所有元素。返回一個迭代器,它指向被刪除元素段後面的元素。如果e本身就是指向超出容器末端的下一個位置,
則返回的迭代器也指向容器末端的下一個位置
c.clear() 刪除容器c內的所有元素。返回voidc.pop_back() 刪除容器c的最後一個元素。返回void。如果容器為空白,則該函數未定義c.pop_front() 刪除容器c的第一個元素。婦女會void。如果容器為空白,則該函數未定義。只適用於list和deque容器
6.容器的賦值與swap操作
下表為順序容器的賦值操作。賦值後左右兩邊容器相等,儘管賦值之前兩個容器的大小不同,但賦值之後兩個容器的長度都為右運算元的長度。
c1=c2 刪除容器c1的所有元素,然後將c2的元素複製給c1。c1和c2的類型必須相同c1.swap(c2) 交換c1和c2的內容,c1和c2的類型必須相同。其效率比把c2元素複製到c1中要高c.assign(b,e) 重新設定c的元素:將迭代器b和e標記範圍內的元素複製到c中。b和e必須不是指向c中元素的迭代器c.assign(n,t) 將容器c重新設定為儲存n個值為t的元素
C++順序容器知識總結