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 |
v2 是v1 的拷貝,包含了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.begin
和end
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
中(所有擁有迭代器的標準庫類型都如此)使用iterator
和const_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)提供的標準庫類型容器就是這樣一個常用數據結構的類模板。
分類
標準庫容器分爲三大類:
- 順序容器(sequential_container)
- 關聯容器(associative container)
- 容器適配器(container adaptor)
3.順序容器
1.順序容器概述
順序容器是一種元素之間有順序關係的線性表,是一種線性結構的可序羣集。順序容器爲程序員提供了控制元素存儲順序和訪問順序的能力,這種順序不依賴於元素的值,而是與元素加入容器時的位置相對應。
標準容器庫中的所有順序容器都提供了快速順序訪問元素的能力,但是不同的容器在向容器中增刪元素或是非順序訪問元素方面略有差異。
要使用不同的順序容器,只需要包含不同的頭文件即可。
容器 | 頭文件 | 含義 | 特性 |
---|---|---|---|
vector |
<vector> |
可變大小數組 | 支持快速隨機訪問。在尾部之外的位置插入或刪除元素可能很慢。 |
deque |
<deque> |
雙端隊列 | 支持快速隨機訪問。在頭尾位置插入或刪除元素很快。 |
list |
<list> |
雙向鏈表 | 只支持雙向順序訪問。 在任何位置進行插入/刪除操作速度都很快。 |
forward_list |
<forward_list> |
單向鏈表 | 只支持單向順序訪問。在任何位置進行插入/刪除操作速度都很快。 |
array |
<array> |
固定大小數組 | 支持快速隨機訪問。不能添加或刪除元素。 |
2.順序容器的選擇
除非有很好的理由選擇其他容器,否則應當使用
vector
以下是一些選擇順序容器的基本原則:
- 除非你有很好的理由選擇其他容器,否則應使用
vector
。 - 如果你的程序有很多小的元素,且空間的額外開銷很重要,則不要使用
list
或forward_list
。 - 如果程序要求隨機訪問元素,應使用
vector
或deque
。 - 如果程序只有在讀取輸入時才需要在容器中間位置插入元素,則
- 首先,確定是否真的需要在容器中間位置添加元素。當處理輸入數據時,通常可以很容易地向
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) |
√ | √ | √ | √ | × | |
大小 | ` |