vector是種容器,類似數組一樣,但它的size可以動態改變。
vector的元素在內存中連續排列,這一點跟數組一樣。這意味著我們元素的索引將非常快,而且也可以通過指針的偏移來獲取vector中的元素。
但連續排列也帶來了弊端,當我們向vector中間插入一個數據時,整個vector的size變大,在內存中就需要重新分配空間,常規的做法是直接申請一個新的array,並將所有元素拷貝過去;但這麼做的話,無疑太浪費時間,因此vector採用的做法是:vector會分配額外的空間,以適應size的動態增長。因此,包含同樣數量元素的vector和數組相比,佔用的空間會更大。而且在vector最後增加或者刪除一個元素,消耗的時間是一個常數值,與vector的size無關。
與其他容器(deques、lists、forward_lists)相比,vector在獲取元素和對最後一個元素的操作效率上更高;但對於中間元素的操作,性能則相對較差。
vector的使用頭文件#include <vector>
std::vector<int> vec1; // 空的vector,數據類型為int
std::vector<int> vec2(4); // 4個值為0的vector
std::vector<int> vec3 (4,10); // 4個值為10的vector [10 10 10 10]
std::vector<int> vec4 (vec3.begin(),vec3.end()); // [10 10 10 10]
std::vector<int> vec5 (vec3); // [10 10 10 10]
std::vector<int> vec6 = {10, 20, 30, 40}; // [10 20 30 40]
Iterators
NameDescriptionbegin返回指向迭代器第一個元素的指針end返回指向迭代器最後一個元素的指針rbegin返回迭代器逆序第一個元素的指針rend返回迭代器逆序最後一個元素的指針cbegin返回常量迭代器的第一個元素的指針cend返回常量迭代器的最第一個元素的指針crbegin返回常量迭代器逆序的第一個元素的指針crend返回常量迭代器逆序的最後一個元素的指針Capacity
NameDescriptionsize返回當前vector使用數據量的大小max_size返回vector最大可用的數據量resize調整vector中的元素個數capacity返回vector中總共可以容納的元素個數empty測試vector是否是空的reserve控制vector的預留空間shrink_to_fit減少capacity到size的大小Element access
NameDescriptionoperator[]在[]中可以做運算atvector.at(i)相當於vector[i]front返回第一個元素的值back返回最後一個元素的值data返回指向vector內存數據的指針Modifiers
NameDescriptionassign指定vector內容push_back在容器的最後一個位置插入元素xpop_back刪除最後一個元素insert插入元素erase擦除元素swap交換兩個容器的內容clear將容器裡的內容清空,size值為0,但是存儲空間沒有改變emplace插入元素(與insert有區別)emplace_back在容器的最後一個位置插入元素x(與push_back有區別)Allocator
NameDescriptionget_allocator返回vector的內存分配器Iterators
Iterators使用方式比較簡單,下面的程序也很直觀的展現了它們的用法。其中it3和it4在for中使用auto來定義,使用更加方便。
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec0;
for (int i = 0; i < 10; ++i) {
vec0.push_back(i); //[0,1,2,3,4,5,6,7,8,9]
}
vector<int>::iterator it1;
for (it1 = vec0.begin(); it1 != vec0.end(); ++it1) {
cout << ' ' << *it1 << endl; //[0,1,2,3,4,5,6,7,8,9]
}
vector<int>::reverse_iterator it2;
for (it2 = vec0.rbegin(); it2 != vec0.rend(); ++it2) {
cout << ' ' << *it2 << endl; //[9,8,7,6,5,4,3,2,1,0]
}
for (auto it3 = vec0.cbegin(); it3 != vec0.end(); ++it3) {
cout << ' ' << *it3 << endl; //[0,1,2,3,4,5,6,7,8,9]
}
for (auto it4 = vec0.crbegin(); it4 != vec0.crend(); ++it4) {
cout << ' ' << *it4 << endl; //[9,8,7,6,5,4,3,2,1,0]
}
return 0;
}
如果是vec0.begin()+1,則表示從第二個元素開始。
Capacity
Capacity中的幾個函數,從描述上看有點模糊,下面我們具體解釋一下。
size返回的是當前vector中有多少元素;
max_size返回的是最大可用的數據量,這跟實際的硬體有關,但也並不是所有的內存空間都可用,比如下面程序中的運行的內存大小為32GByte,但返回的結果是4GByte;
capacity是當前vector分配的可以容納的元素個數,下面的代碼中,vec0可以容納13個元素,但僅包含了size(即10)個元素,還有3個元素可以放進去,當再放入超過3個元素後,vec0就會被重新分配空間;所以,capacity始終大於等於size;
resize把容器改為容納n個元素。調用resize之後,size將會變為n;其中n又分了三種情況,當n
<size時,容器尾部的元素會被銷毀,capacity保持不變;當size<n≤capacity時,新增加的元素都是0,capacity保持不變;當n style="font-size: inherit;color: inherit;line-height: inherit;">capacity時,size和capacity同時變為n,新增加的元素都是0;</size時,容器尾部的元素會被銷毀,capacity保持不變;當size<n≤capacity時,新增加的元素都是0,capacity保持不變;當n>empty比較簡單,當vector為空時,返回1,不為空返回0;
shrink_to_fit,去掉預留的空間,capacity與size保持一致
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec0;
cout << "vec0 empty status:" << vec0.empty() << endl; // 1
for (int i = 0; i < 10; ++i) {
vec0.push_back(i); //[0,1,2,3,4,5,6,7,8,9]
}
cout << "vec0 empty status:" << vec0.empty() << endl; // 0
//Capacity-
cout << "vec0 size:" << vec0.size() << endl; //10
cout << "vec0 max size:" << vec0.max_size() << endl; //1073741823 = 4GByte
cout << "vec0 capacity:" << vec0.capacity() << endl; //13
vec0.resize(20);
cout << "new size:" << vec0.size() << " new capacity:" << vec0.capacity() << endl; //20 20
vec0.resize(5);
cout << "new size:" << vec0.size() << " new capacity:" << vec0.capacity() << endl; // 5 20
vec0.shrink_to_fit();
cout << "new size:" << vec0.size() << " new capacity:" << vec0.capacity() << endl; // 5 5
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
int main() {
//reserve----
std::vector<int> vec0;
int sz;
sz = vec0.capacity();
std::cout << "making vec0 grow:\n";
for (int i = 0; i < 100; ++i) {
vec0.push_back(i);
if (sz != vec0.capacity()) {
sz = vec0.capacity();
std::cout << "capacity changed: " << sz << '\n';
}
}
std::vector<int> vec1;
sz = vec1.capacity();
vec1.reserve(100); // this is the only difference with vec0 above
std::cout << "making vec1 grow:\n";
for (int i = 0; i < 100; ++i) {
vec1.push_back(i);
if (sz != vec1.capacity()) {
sz = vec1.capacity();
std::cout << "capacity changed: " << sz << '\n';
}
}
return 0;
}
列印結果為:
making vec0 grow:
capacity changed: 1
capacity changed: 2
capacity changed: 3
capacity changed: 4
capacity changed: 6
capacity changed: 9
capacity changed: 13
capacity changed: 19
capacity changed: 28
capacity changed: 42
capacity changed: 63
capacity changed: 94
capacity changed: 141
making vec1 grow:
capacity changed: 100
Element access
vector元素獲取的使用方法也比較簡單,下面的代碼可以很好的展示:
vector<int> vec0;
for (int i = 0; i < 10; ++i) {
vec0.push_back(i); //[0,1,2,3,4,5,6,7,8,9]
}
for (unsigned int i = 0; i < vec0.size(); ++i) {
cout << vec0.at(i) << endl; //[0,1,2,3,4,5,6,7,8,9]
}
cout << "front element:" << vec0.front() << endl; //0
cout << "back element:" << vec0.back() << endl; //9
vector<int>vec1(5); // [0,0,0,0,0]
int *p = vec1.data(); // vec1 must not be empty
for (unsigned int i = 0; i < vec1.size(); ++i) {
*p = i;
++p;
}
for (unsigned int i = 0; i < vec1.size(); ++i) {
cout << vec1[i] << endl; // [0,1,2,3,4]
}
Modifiers
assign主要有三種用法,如下面的demo所示:
vector<int> vec1;
vector<int> vec2;
vector<int> vec3;
vec1.assign(5, 10); //[10,10,10,10,10]
vector<int>::iterator it;
it = vec1.begin() + 1;
vec2.assign(it, vec1.end() - 1); //[10,10,10]
int arr[] = { 10,20,30,40};
vec3.assign(arr, arr + 4); //[10,20,30,40]
push_back和pop_back用法比較簡單
vec0.push_back(55);
cout << "Last element:" << vec0.back() << " size: " << vec0.size()<< endl; //55 11
vec0.pop_back();
cout << "Last element:" << vec0.back() << " size: " << vec0.size() << endl; //9 10
在vector中,有插入元素功能的函數有四個:push_back、insert、emplace和emplace_back,其中push_back上面講了,emplace_back是在C++11中引入的,用法跟push_back完全一樣,都是在vector的最後插入一個元素。
vec3.emplace_back(100);
那為什麼要引入一個用法完全一樣的函數?因為它們的底層實現方式不同,push_back向容器尾部添加元素時,然後再將這個元素拷貝或者移動到容器中(如果是拷貝的話,事後會自行銷毀先前創建的這個元素);而 emplace_back 在實現時,則是直接在容器尾部創建這個元素,省去了拷貝或移動元素的過程。
insert和emplace(C++11中引入)都可以向vector中間插入元素,但insert可以插入多個元素,emplace一次只能插入一個元素。
insert有三種用法:
在指定位置loc前插入值為val的元素,返回指向這個元素的迭代器,
在指定位置loc前插入num個值為val的元素
在指定位置loc前插入區間[start, end)的所有元素
// method1
vector<int> vec1;
int arr[] = { 1,2,3,4,5 };
vec1.insert(vec1.begin(), arr, arr + 5); //[1,2,3,4,5]
// method2
vector<int> vec2(vec1);
vector<int>::iterator it = vec1.begin() + 2;
vec1.insert(it, 3, 20); // [1,2,20,20,20,3,4,5]
// method3
vector<int> vec3(3, 40);
vector<int>::iterator it2 = vec2.begin();
vec2.insert(it2, vec3.begin(), vec3.end()); // [40,40,40,1,2,3,4,5]
emplace的使用方式為:
iterator emplace (const_iterator pos, args...);
vector<int> vec0{1,2,3};
vec0.emplace(vec0.begin()+2,10); //[1,2,10,3]
若都是插入一個元素的情況下,該使用哪個函數呢?當然是C++11中新引入的emplace,emplace在插入元素時,在指定位置直接構造元素,而insert是生成元素,再將其賦值或移動到容器中。
vector中有三種可以刪除元素的操作,第一種就是我們上面講到的pop_back,刪除最後一個元素,無返回值;第二種是clear,將容器清空,size變為0,無返回值;第三種是erase,通過迭代器來刪除元素,可以刪除一個元素,也可以刪除某個範圍內的元素,返回下一個位置的迭代器。
vector<int> vec0{ 1,2,3,4,5,6,7,8,9,10};
//for (int i = 0; i < 4; ++i) {
// vec0.pop_back();
//}
vec0.erase(vec0.begin() + 3); // [1,2,3,5,6,7,8,9,10]
vec0.erase(vec0.begin(), vec0.begin() + 5); // [7,8,9,10]
//vec0.clear();
swap的用法也比較簡單,就是交換兩個vector的內容
vector<int> vec1{ 1,2,3,4,5 };
vector<int> vec2{ 10,20,30 };
vec1.swap(vec2);
Allocator
get_allocator用的不是特別多,我們把使用方法講一下。
vector<int> myvector;
int * p;
unsigned int i;
// 使用Allocator為數組分配5個元素的空間
p = myvector.get_allocator().allocate(5);
for (i=0; i<5; i++) myvector.get_allocator().construct(&p[i],i);
std::cout << "The allocated array contains:";
for (i=0; i<5; i++) std::cout << ' ' << p[i]; //[0,1,2,3,4]
for (i=0; i<5; i++) myvector.get_allocator().destroy(&p[i]);
myvector.get_allocator().deallocate(p,5);
上面我們講的,都相當於是一維數組,vector還支持二維數組,但這種二維數組是通過嵌套的方式來實現,並不像Python或者Matlab的矩陣那麼直觀。
vector<vector<int>> arr(3);
for (int i = 0; i < 3; ++i) {
arr[i].resize(3); //3x3 array
}
for (int i = 0; i < 3; ++i)
for (int k = 0; k < 3; ++k)
arr[i][k] = i * k; // 賦值
arr.resize(4); // 二維數組包含4個變量
arr[2].resize(5); // 第3個變量包含5個變量