[C++]標準庫類型容器

update:2016/11/16

1.標準庫類型vector

vector能夠容納絕大多數類型的對象作爲其元素,但是由於引用並不是對象,因此不存在包含引用的vector。除此之外,其他大多數(非引用)內置類型和類類型都可以作爲vector的元素,這也包含vector

1.定義和初始化vector

vector作爲一個類模板,本身不會指定類型,而必須要爲其指定類型。例如:

vector<int> ivec;  //保存int類型的對象
vector<Sales_item> Sales_vec; //保存Sales_item類型的對象
vector<vector<string>> file; //保存vector對象的vector

初始化一個vector對象的常用方法如下:

初始化vector語句 含義解釋
vector<T> v1 v1是一個空vector,執行默認初始化
vector<T> v2(v1) v2使用v1的值初始化,包含了v1的所有元素
vector<T> v2=v1 v2v1的拷貝,包含了v1的所有元素
vector<T> v3(n) v3包含了n個元素,執行了值初始化
vector<T> v4(n,val) v4包含了n個重複的元素,每個元素的值都是val
vector<T> v5{a,b,c...} v5的元素按順序賦予初始值,執行列表初始化
vector<T> v5={a,b,c...} v5使用列表的拷貝進行初始化。

1. 默認初始化

vector默認初始化可以提供一個空的容器,方便之後對其進行任何允許的操作。

vector<int> vector1; 

2. 拷貝初始化

vector執行拷貝初始化可以在初始化時將一個已存在的vector元素的值拷貝給新的vector對象。此時新的vector中的元素就是原vector對象對應元素的副本。

//assume that an int vector {1,2,3,4,5} called vector1 has been defined.
//then the following codes are equivalent to each other.
vector<int> vector2=vector1;
vector<int> vector3(vector1);
vector<int> vector4{vector1};
  • 拷貝初始化時,兩個vector對象的類型必須相同。

3. 列表初始化

vector執行列表初始化時,可以用花括號{}將0個或多個初始元素值括起來,使用其在爲新的vector對象初始化的同時爲其元素賦予初值。

vector<int> vector5{1,2,5,8,0};

4. 值初始化

vector執行值初始化,可以用圓括號()vector容納的元素數量和所有元素的統一值括起來,使用其在爲新的vector對象初始化的同時,創建指定數量的元素。
在爲vector進行值初始化時,首先由編譯器創建一個經過初始化的元素初值,並將其賦給容器中的所有元素。

  • 可以將元素值省略,即用括號()vector對象容納的元素數量括起來。在缺省元素初值的情況下,元素初值由vector對象中的元素類型決定:如果vector對象的元素是內置類型,則元素初始值設爲0;如果元素是某種類類型,則元素由類的默認構造函數進行初始化。總之,在缺省元素初值的情況下,創建一個經過默認初始化的元素初值,並將其賦給容器中的所有元素。
vector<int> vector6(10);
vector<int> vector7(10,12);

5.構造還是初始值列表?

初始化的真實含義依賴於傳遞初始值時使用的是花括號{}亦或是圓括號():

  • ()表示使用參數來構造一個vector對象。
  • {}表示參數是一個初始值列表
//the deference between () and {}
vector<int> myVector1(10,3); //10 elements:3,3,3,3,3,3,3,3,3,3
vector<int> myVector2{10,3}; //2 elements:10,3

2.vector的迭代器

迭代器(iterator)是一種能夠檢查容器內元素並遍歷元素的數據類型。
如同我們使用過的指針,迭代器可以提供對對象的間接訪問。事實上,從面向對象的角度而言,迭代器是一個基類,而指針則是這個基類的一個派生類。通過使用迭代器,我們可以在不知道對象內部表示的情況下(間接)按照一定的順序訪問一個容器的所有元素(遍歷)。

2.1vector迭代器的使用

和指針不一樣的是,我們可以不必關注元素的地址。vector在擁有迭代器的同時,還提供了返回迭代器的成員函數(運算符)。

1.beginend

begin成員返回指向頭元素的迭代器。
end成員返回指向尾元素的下一位置的迭代器(尾後迭代器)。

    vector<T> myVec = {1, 2, 3, 4, 5}
    auto begin = myVec.begin(), end = myVec.end();
  • 如果調用begin()end()的是空容器,則二者都返回尾後迭代器。

2.vector迭代器支持的運算

我們提到了vector的迭代器事實上是一種數據類型,於是對於這樣的一個數據類型一定支持一定的運算(操作),下面列出vector的迭代器所有支持的運算(以下iter代表某個迭代器類型變量):

運算符 操作
*iter 對迭代器iter解引用
iter->mem 解引用iter名爲mem的成員,相當於(*iter).mem
iter++ iter指示容器中的下一個元素
iter-- iter指示容器中的上一個元素
iter + n iter指示原位置向下移動了n個元素
iter - n iter指示原位置向上移動了n個元素
iter += n iter + n的結果賦給iter
iter -= n iter - n的結果賦給iter
iter1 - iter2 兩個指示同一容器的迭代器相減得到所指示元素之間的距離
iter1 == iter2 判斷兩個迭代器是否指示同一個元素或相同容器的尾後迭代器
iter1 != iter2 判斷兩個迭代器是否指示同一個元素或相同容器的尾後迭代器
>,>=,<,<= 兩個指示同一容器的迭代器,iter1指示的元素在iter2指示元素 之後,就說iter1 > iter2

2.2 迭代器類型

一般來說,我們無需知道vector的迭代器的精確類型。想要獲得一個指示int向量的通常做法會是這樣:

    // to get an iterator of iVec;
    vector<int> iVec{1, 2, 3, 4, 5};
    // use type auto to declare the iterator;
    auto bg = ivec.begin(); 
    int n = 2;
    bg += n;

而實際上,在vector中(所有擁有迭代器的標準庫類型都如此)使用iteratorconst_iterator表示迭代器的類型。const_iterator類似於我們熟悉的常量指針(頂層const),能讀取但不能修改它所指示的元素值。

  • 如果容器是一個常對象,則只能使用const_iterator;如果容器不是常對象,則既可以使用iterator也可以使用const_iterator,唯一的區別在於前者指示的對象可讀可寫,而後者指示的對象只可讀不可寫
  • begin()end()運算符返回的具體類型由容器對象是否爲常對象決定:如果是常對象,begin()end()返回const_iterator;否則返回iterator

3.迭代器的失效

任何一個可能改變vector對象容量的操作都會使該vector對象的迭代器失效。

3.vector上的一些操作

操作 說明
vector.empty() 如果vector爲空容器,返回true,否則返回false
vector.size() 返回vector中的元素個數
vector.push_back(t) vector的尾端(拷貝地)添加一個值爲t的元素,返回指向新添加元素的迭代器
vector.emplace_back(args) vector的尾端(構造地)添加一個由arg創建的元素,返回指向新添加元素的迭代器
vector[n] 返回vector中第n個位置上元素的引用

2.標準庫類型容器概述

容器(container)是包含對象的數據結構類模板。把數組(array)、隊列(queue)、鏈表(list)、堆棧(stack)、樹(tree)、圖(tree)等數據結構中的每個節點(都是對象)組織起來,稱爲一個新的對象。如果抽象了這些數據元素的具體類型,只關心結構的組織,就成爲一個類模板。標準模板庫(standard template library,STL)提供的標準庫類型容器就是這樣一個常用數據結構的類模板。

分類

標準庫容器分爲三大類:

3.順序容器

1.順序容器概述

順序容器是一種元素之間有順序關係的線性表,是一種線性結構的可序羣集。順序容器爲程序員提供了控制元素存儲順序訪問順序的能力,這種順序不依賴於元素的值,而是與元素加入容器時的位置相對應。
標準容器庫中的所有順序容器都提供了快速順序訪問元素的能力,但是不同的容器在向容器中增刪元素或是非順序訪問元素方面略有差異。
要使用不同的順序容器,只需要包含不同的頭文件即可。

容器 頭文件 含義 特性
vector <vector> 可變大小數組 支持快速隨機訪問。在尾部之外的位置插入或刪除元素可能很慢。
deque <deque> 雙端隊列 支持快速隨機訪問。在頭尾位置插入或刪除元素很快。
list <list> 雙向鏈表 只支持雙向順序訪問。 在任何位置進行插入/刪除操作速度都很快。
forward_list <forward_list> 單向鏈表 只支持單向順序訪問。在任何位置進行插入/刪除操作速度都很快。
array <array> 固定大小數組 支持快速隨機訪問。不能添加或刪除元素。

2.順序容器的選擇

除非有很好的理由選擇其他容器,否則應當使用vector

以下是一些選擇順序容器的基本原則:

  • 除非你有很好的理由選擇其他容器,否則應使用vector
  • 如果你的程序有很多小的元素,且空間的額外開銷很重要,則不要使用listforward_list
  • 如果程序要求隨機訪問元素,應使用vectordeque
  • 如果程序只有在讀取輸入時才需要在容器中間位置插入元素,則
    • 首先,確定是否真的需要在容器中間位置添加元素。當處理輸入數據時,通常可以很容易地向vector追加數據,然後再調用標準庫的sort 函數來重排容器中的元素,從而避免在中間位置添加元素。
    • 如果必須在中間位置插入元素,考慮在輸入截斷使用list,一旦輸入完成,將list中的內容拷貝到一個vector中。

3.順序容器的使用(一)

4.順序容器的操作

把所有順序容器支持的操作列表如下:

    vector deque list forward_list array
構造函數 Container con
Container con1(con2)
Container con(beg,end) ×
Container con{a,b,c...}
賦值與swap con1 = con2
con = {a,b,c...} ×
con1.swap(con2)
swap(con1,con2)
con.assign(beg,end) ×
con.assign(initial_list) ×
con.assign(n,t) ×
大小 `
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章