1. 程式人生 > 實用技巧 >c++ 順序容器常用知識總結

c++ 順序容器常用知識總結

c++順序容器常用知識總結:

目錄

正文

  容器是一種容納特定型別物件的集合。C++的容器可以分為兩類:順序容器和關聯容器。順序容器的元素排列和元素值大小無關,而是由元素新增到容器中的次序決定的。標準庫定義了三種順序容器的型別:vector、list和deque(雙端佇列)。此外,標準庫還提供了三種容器介面卡:stack、queue和prioroty_queue型別。介面卡是根據原始的容器型別所提供的操作,通過定義新的操作介面,來適應基礎的容器型別。見下表

順序容器
vector
//可變大小陣列,支援快速隨機訪問,在尾部之外的位置插入或刪除元素 可能很慢 deque //雙端佇列,支援快速隨機訪問,在頭尾位置插入或刪除元素很快 list //雙向連結串列,支援雙向順序訪問,在list任何位置插入或刪除元素都很快

順序容器介面卡
stack                     //後進先出(LIFO)棧
queue                     //先進先出(FIFO)佇列
priority_queue            //有優先順序管理的佇列

forward_list //
單向連結串列,只支援單向順序訪問,在任何位置插入或刪除元素都很快 array //固定大小陣列,支援快速隨機訪問,不能新增或刪除元素 string //與vector類似,但專用於儲存字元。隨機訪問快。在尾部刪除/插入速度快。 //list與forward_list不支援元素的隨機訪問

ps:有關於unsingned int 與 size_t的有關區分

  • size_t 是什麼啥?

它是一個與機器相關的unsigned型別,其大小足以保證儲存記憶體中物件的大小。

size_t 型別定義在cstddef標頭檔案中

size_t的全稱應該是size type,就是說“一種用來記錄大小的資料型別”

例子:

通常我們用sizeof(XXX)操作,這個操作所得到的結果就是size_t型別

void *malloc(size_t n);

void *memcpy(void *s1, void const *s2, size_t n);

size_t strlen(char const *s);

  • size_t 大小

size_t的真實型別與作業系統有關。

在32位架構中被普遍定義為:

typedef unsigned int size_t;

在32位架構上是4位元組

在64位架構中被定義為:

typedef unsigned long size_t;

在64位架構上是8位元組

  • size_t 是無符號的

size_t為無符號數

  • size_t和int區別

int在不同架構下都是4位元組,與size_t不同

int為帶符號數,size_t為無符號數。

  1. 為什麼有時候不用int,而是用size_type或者size_t:

因為:

size_t的取值range是目標平臺下最大可能的陣列尺寸

使用Int既有可能浪費,又有可能範圍不夠大

  • size_t 優點

使用size_t可能會提高程式碼的可移植性、有效性或者可讀性,或許同時提高這三者。

細節詳情請看:https://jeremybai.github.io/blog/2014/09/10/size-t

一.定義和初始化

  定義一個容器型別的物件之前,必須包含相關的標頭檔案。如下:

#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 *);    
             //  使用整個陣列初始化words
list<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,3
list<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_type
c.max_size()            返回容器c可以容納的最多的元素個數.返回型別為c::size_type
c.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內的所有元素。返回void
c.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的元素