vector的介紹和使用
- 一.vector的檔案介紹
- 二.vector的使用
- 1.vector物件的創建
- 2.迭代器 iterator的使用
- 3.vector空間
- 4.vector的增刪查改
- 三.迭代器失效的問題
一.vector的檔案介紹
-
vector是表示可變大小陣列的序列容器,
-
就像陣列一樣,vector也采用的連續存盤空間來存盤元素,也就是意味著可以采用下標對vector的元素
進行訪問,和陣列一樣高效,但是又不像陣列,它的大小是可以動態改變的,而且它的大小會被容器自
動處理, -
本質講,vector使用動態分配陣列來存盤它的元素,當新元素插入時候,這個陣列需要被重新分配大小
為了增加存盤空間,其做法是,分配一個新的陣列,然后將全部元素移到這個陣列,就時間而言,這是
一個相對代價高的任務,因為每當一個新的元素加入到容器的時候,vector并不會每次都重新分配大
小, -
vector分配空間策略:vector會分配一些額外的空間以適應可能的增長,因為存盤空間比實際需要的存
儲空間更大,不同的庫采用不同的策略權衡空間的使用和重新分配,但是無論如何,重新分配都應該是
對數增長的間隔大小,以至于在末尾插入一個元素的時候是在常數時間的復雜度完成的, -
因此,vector占用了更多的存盤空間,為了獲得管理存盤空間的能力,并且以一種有效的方式動態增
長, -
與其它動態序列容器相比(deques, lists and forward_lists), vector在訪問元素的時候更加高效,在
末尾添加和洗掉元素相對高效,對于其它不在末尾的洗掉和插入操作,效率更低,比起lists和
forward_lists統一的迭代器和參考更好,
簡單來說,vector就類似于我們資料結構中的線性表,它可以動態增容,
二.vector的使用
1.vector物件的創建
創建vector物件的模板:vector<型別名> 物件,其中的型別名可以是任意型別,如int,char,double,string等等,
如下:
void vectortest()
{
vector<int> v1(3, 3);//創建一個v1的物件,里面存盤的是int型別的資料
vector<char>v2(3, 'a');//創建一個v1的物件,里面存盤的是char型別的資料
vector<string>v3(3, "張三");//創建一個v1的物件,里面存盤的是string型別(字串)的資料
}
通過除錯,可以看出v1存盤3個int型別的資料,v2存盤3個char型別的資料,v3存盤3個string型別的資料,

| 建構式宣告 | 介面說明 |
|---|---|
| vector() | 無參的建構式 |
| vector(const vector v) | 拷貝構造 |
| vector (InputIterator first, InputIterator last) | 使用迭代器進行初始化構造 |
| vector(size_type n, const value_type& val = value_type()) | 構造并初始化n個val |
void vectortest1()
{
vector<int> v1;//無參構造
vector<int> v2(10, 3);//構造并初始化10個3
vector<int>v3(v2);//拷貝構造
vector<int>v4(v2.begin(), v2.end());//利用迭代器將v2中的資料構造出v4
}
2.迭代器 iterator的使用
| 專案 | 說明 |
|---|---|
| begin()+end() | begin()回傳的是vector物件的第一個資料地址,end()回傳的是最后一個資料的下一位置的地址 |
| rbegin()+rend() | rbegin()獲取的是vector物件的最后一個資料的地址,rend()獲取的是vector物件第一個資料的前一個位置的地址, |


3.vector空間
| 介面 | 介面說明 |
|---|---|
| empty | 判斷是否為空 |
| size | 獲取資料個數 |
| capacity | 獲取容量的空間大小 |
| resize | 改變size的大小 |
| reserve | 改變容量的大小 |
void vectortest()
{
vector<int> v1(3, 3);
cout << v1.size() << endl;//獲取v1中的資料個數為3
cout << v1.capacity() << endl;//獲取v1中的容量為3
v1.resize(10);//將v1的size從3變為10,同時capacity也會從10變為20
v1.
cout << v1.size() << endl;//獲取v1中的資料個數為10
cout << v1.capacity() << endl;//獲取v1中的容量為10
v1.reserve(20);//將capacity從10變為20,size不變
cout << v1.size() << endl;//獲取v1中的資料個數為10
cout << v1.capacity() << endl;//獲取v1中的容量為20
}
補充:
1.capacity的代碼在vs和g++下分別運行會發現,vs下capacity是按1.5倍增長的,g++是按2倍增長的,c++標準只是定義vector和它的介面的功能,但每個編譯器底下實作這些介面函式的可能會有所差異,所以一段相同的代碼在vs編譯器可能運行得起來,在linux下可能運行不起來,也可能某些數運行出來有所差異,
2.reserve只負責開辟空間,如果確定知道需要用多少空間,reserve可以緩解vector增容的代價缺陷問題,
4.vector的增刪查改
| 介面 | 介面說明 |
|---|---|
| push_back | 尾插資料 |
| pop_back | 尾刪資料 |
| insert | 在position之前插入一個資料 |
| erase | 洗掉position位置的資料 |
| swap | 交換兩個vector的資料空間 |
| operator[] | 像陣列一樣去訪問vector的資料 |
| find | 查找,這個不是vector上的介面函式,而是在演算法里面的., |

注明:任何容器都可以使用find,只要傳迭代器給它,它就可以在這個迭代區間進行查找某個資料,找到了就回傳地址,如果找不到,就回傳end(),
輸出的結果:
void vectortest4()
{
vector<int> v1(3, 1);//創建v1,并初始化3個1
vector<int> v2(4, 2);//創建v2,并初始化4個2
v1.swap(v2);//將v1和v2中的資料進行交換,包括capacity和size
}
三.迭代器失效的問題
迭代器(iterator)是一個可以對其執行類似指標的操作(如:解除參考(operator*())和遞增(operator++()))的物件,我們可以將它理解成為一個指標,
什么是迭代器失效呢?我們先來看一個例子:
void vectortest4()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);//v1中尾插4個資料
vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);
v1.insert(pos, 0);//在3的位置之前插入一個0,此時pos位置指向的資料就變為0,此時迭代器失效
}
1.第一種情況:我們通過迭代器找到3的位置pos,然后在pos位置插入0,插入0之后,pos指向的資料就由3變成0了,迭代器就失效了,我們再去用這個迭代器pos,有的編譯器就會報錯,

2.第二種情況:我們通過迭代器找到3的位置pos,然后將3給刪掉,這時迭代器pos指向的資料就變為4,同樣,迭代器也會失效,

3.第三種情況:我們通過迭代器找到3的位置pos,然后在通過pos在3之前插入一個0,但是v1容量已經最大,此時就需要增容,就先開辟一塊更大的空間,把久空間的資料拷貝給新空間,再把久空間給處理掉,所以pos就變為野指標(在vector底下層,迭代器就是指標),這時候迭代器也失效,不能再用它

總結:1.如果我們利用迭代器將在某個資料之前插入一個資料之后,或者利用迭代器洗掉某個資料之后,迭代器指向內容就會改變,也就是迭代器的意義改變,迭代器就失效,就有可能引發錯誤,
2.如果想插入某個資料,出現增容的情況,pos指向的空間已經釋放,此時的pos就變成野指標,迭代器也失效
所以:迭代器失效的解決辦法是:在使用之前,對迭代器重新賦值即可,
寫一段代碼,洗掉vector中的所以偶數
接下來我們在看一下下面這段代碼是否正確:
int main()
{
vector<int> v{ 1, 2, 3, 4 };
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
v.erase(it);
++it;
}
return 0; }
在vs測驗了一下,發現這段代碼會奔潰,為什么呢?
我們在洗掉資料時,后面的資料就會往前挪動,end()也會向前挪動一步,然后it在++,如果洗掉最后一個位置的資料,此時it和end()就不會相遇,最終程式奔潰,

所以我們對代碼改動一下,如果洗掉時,it就不會走一步,沒有洗掉,it才走一步
int main()
{
vector<int> v{ 1, 2, 3, 4 };
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
it = v.erase(it);
else
++it;
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/292088.html
標籤:其他
上一篇:C語言中奇妙又有趣的符號——運算子(運算子)!C語言運算(操作)符最全集合(建議收藏)
下一篇:[C語言]陣列詳解
