目錄
一、簡介
vector,是同一類型的對象的集合,這一集合可看作可變大小的數組,是容器的一種。
- 對於容器來說,其重要特性之一便是於可以在運行時高效地添加元素。
- 類似於數組,vector采用連續內存地址來存儲元素,因此vector屬於順序容器。也就意味着可以采用下標對vector的元素進行訪問,和數組一樣高效;同時它比數組更加靈活,它的大小(size)是可以動態改變的,且它的大小會被容器自動處理。
- vector分配空間策略:vector會分配一些額外的空間以適應可能的增長,使得分配的存儲空間(capacity)比實際需要的存儲空間更大。不同的庫采用不同的策略權衡空間的使用和重新分配,vc里是每次增大當前capacity的一半。但是無論如何,重新分配總是對數增長的間隔大小,在末尾插入一個元素的時候則能夠在常數時間的復雜度完成的。
- 在這里應理解好size與capacity之間的關系,這將有助於理解
vec.resize()
與vec.reserve()
的區別:- 容器的capacity是其size的上界,size總是<=capacity;當所需求的size>當前capacity時,vector便會如上文所述一般對capacity進行動態分配,以滿足目標size需求。
- 我們使用
[]
操作符時,只能訪問size大小內的容器空間,這才是真正存在對象的內存空間;而>size同時<capacity的內存則屬於“野”內存。
- 與其它動態序列容器相比(deques, lists and forward_lists), vector在訪問元素的時候更加高效,在末尾添加和刪除元素相對高效。對於其它不在末尾的刪除和插入操作,效率更低。比起lists和forward_lists統一的迭代器和引用更好。
二、用法
1. 頭文件
#include<vector>
2. vector的聲明及初始化
(1)不帶參數的構造函數初始化
// 初始化一個size為0的vector
vector<int> vec;
(2)帶參數的構造函數初始化
僅指定vector大小,此時每個元素值為默認值0
vector<int> vec(10); //初始化了10個默認值為0的元素
指定vector大小和元素初始值
vector<int> vec(10,1); //初始化了10個值為1的元素
// 或是
vettor<int> vec = {1, 2, 3}; //初始化了1,2,3這3個元素
(3)通過同類型的vector初始化
vector<int> temp(5,1);
// 通過temp容器初始化一個元素相同的vec向量
vector<int> vec(temp);
通常來說,前三種便足夠我們平時使用了。
(4)通過數組地址初始化
int a[5] = {1,2,3,4,5};
// 以數組a的元素初始化vector,注意地址是從0到5(左閉右開區間)
vector<int> vec(a, a+5);
(5)通過insert函數初始化
使用同類型的vector以及insert函數初始化
// insert初始化方式將同類型的迭代器對應的始末區間(左閉右開區間)內的值插入到vector中
vector<int> temp(6,6);
vecot<int> vec;
// 將temp[0]~a[2]插入到vec中,vec.size()由0變為3
vec.insert(vec.begin(), temp.begin(), temp.begin() + 3);
使用數組以及insert函數初始化
int a[6] = {6,6,6,6,6,6};
vector<int> vec;
// 將a的所有元素插入到vec中
vec.insert(vec.begin(), a, a+7);
通過insert函數添加m個值為n的元素
// 在vec開始位置處插入6個1
vec.insert(vec.begin(), 6, 1);
(6)通過copy函數賦值
vector<int> vec(5,1);
int a[5] = {2,2,2,2,2};
vector<int> target(10);
// 將vec中元素全部拷貝到target開始的位置中,注意拷貝的區間為vec.begin() ~ vec.end()的左閉右開的區間
copy(vec.begin(), vec.end(), target.begin());
// 拷貝區間也可以是由數組地址構成的區間
copy(a, a+5, vec.begin() + 5);
3. vector基本操作
1)容量相關
- 容器目前大小:
vec.size()
- 容器目前容量:
vec.capacity()
- 容器最大允許容量:
vec.max_size();
- 判斷容器是否為空:
vec.empty()
- 請求容器capacity減少至size大小:
vec.shrink_to_fit()
- 更改容器容量:
vec.reverse(size_type n)
- 更改容器大小
- 目標size小於當前size則截取前目標size個元素;大於則以元素填充存儲空間至目標size
vec.resize(size_type n)
僅指定size修改后大小n,需元素填充則以默認值0填充vec.resize(size_type n, value_type val)
指定目標size大小n以及填充元素的值val
2)修改元素
- 末尾添加元素:
vec.push_back(value_type val)
- 末尾刪除元素:
vec.pop_back()
- 對容器賦值:
vec.assign(const_iterator first, const_iterator last)
將同類型容器目標區間[first, last)內的元素賦給調用者vec.assign(size_type n, const T& x = T())
將n個x賦給調用者
- 在指定位置插入元素:
vec.insert(const_iterator position, value_type& val)
在指定位置position插入元素valvec.insert(const_iterator position, size_type n, value_type& val)
在指定位置position插入n個元素valvec.insert(const_iterator position, InputIterator first, InputIterator last)
在指定位置插入同類型容器目標區間內的元素
- 在指定位置刪除元素
vec.erase(const_iterator position)
刪除指定位置的素vec.erase(const_iterator first, const_iterator last)
刪除指定區間內的元素
- 與另一個容器交換元素:
vec.swap(vector& x)
- 清空容器元素:
vec.clear()
- 調用這個方法后,vec的size置為0但capacity不一定會重新分配
3)使用迭代器
- 聲明迭代器(類似指針):
vector<size_type>::Iterator i
- 訪問迭代器指向的元素:
*i
- 訪問迭代器指向的元素:
- 可寫迭代器
- 指向容器開頭:
vec.begin()
- 指向容器結尾(指向最后一個元素再往后的一個內存):
vec.end()
- 指向容器開頭:
- 只讀迭代器(不能通過該指針來修改元素)
- 指向容器開頭:
vec.cbegin()
- 指向容器結尾:
vec.cend()
- 指向容器開頭:
4)訪問元素
- 訪問指定位置元素。通過下面兩個方法的比較可以看到,我們平時應優先使用
vec.at(i)
:vec[i]
下標訪問。不會下標檢查是否越界,越界時返回一串無規律整形。vec.at(i)
通過at函數訪問。如果越界會拋出out of range的異常
- 訪問第一個元素:
vec.front()
- 訪問最后一個元素:
vec.back()
- 返回一個元素組成的數組的指針:
int* p = vec.data()
4. 常用操作
1)遍歷元素
```
vector<int>::iterator it;
for (it = vec.begin(); it != vec.end(); it++) {
cout << *it << endl;
}
//或者
for (size_t i = 0; i < vec.size(); i++) {
cout << vec.at(i) << endl;
}
```
2)元素翻轉
```
#include <algorithm>
reverse(vec.begin(), vec.end());
```
3)元素排序
```
#include <algorithm>
sort(vec.begin(), vec.end()); //采用的是從小到大的排序
//如果想從大到小排序,可以采用上面反轉函數,也可以采用下面方法:
bool Comp(const int& a, const int& b) {
return a > b;
}
sort(vec.begin(), vec.end(), Comp);
```
文章最后,我個人認為頭文件<algorithm>
中的reverse()
函數寫得特別優雅,在此貼出源碼
template <class BidirectionalIterator>
void reverse (BidirectionalIterator first, BidirectionalIterator last)
{
while ((first != last) && (first != --last)) {
std::iter_swap (first,last);
++first;
}
}
主要參考資料