Vector的定義
- 向量(Vector)是一個封裝了動態大小數組的順序容器(Sequence Container)。跟任意其它類型容器一樣,它能夠存放各種類型的對象。可以簡單的認為,向量是一個能夠存放任意類型的動態數組。
- vector是對象的集合,其中所有對象的類型都相同。集合中的每個對象都有一個與之對應的索引,索引用于訪問的對象。
- vector是模板而不是類型,由vector生成的類型必須包含vector中元素的類型,比如vector<int>。
- vector不可以將引用作為其元素,因為引用不是對象。
定義和初始化vector對象
- 和任何類型一樣,vector模板模板控制著定義和初始化向量的方法。
Vector<T> v1 | v1是一個空的vector,潛在的元素是T類型的,執行默認初始化 |
Vector<T> v2(v1) | v2中包含v1中所有元素的副本 |
Vector<T> v2 = v1 | 等效于v2(v1),v2中包含v1中所有元素的副本 |
Vector<T> v3(n,val) | v3中包含n個重復的元素,每個元素的數值都是val |
Vector<T> v4(n) | v3包含了n個重復地執行值初始化的對象 |
Vector<T> v5{a,b,c.......} | v5包含了初始值個數的元素,每個元素被賦予相應的初始數值 |
Vector<T> v5={a,b,c.....} | 等效于Vector<T> v5{a,b,c.......} |
- 使用方法,先定義一個空的vector,當運行的時候將獲取到的元素數值逐一添加。
- vector之間進行賦值拷貝,需要逐一一個前提,那就是類型必須是一致的。
vector<int> ivec;vector<int> ivec2(ivec);vector<int> ivec3 = ivec;vector<string>ivec4 = ivec;//錯誤,類型不符合
列表初始化vector對象?
- 使用拷貝初始化時(即使用=),只可以提供一個初始數值
- 使用提供的是一個類內初始值,則可以使用拷貝初始化或者使用花括號的形式進行初始化
- 如果提供的是初始元數值的列表,則只能把初始值都放在圓括號里面進行列表初始化,但是不能放在圓括號里面。
- 例如: vector<string> v1 = {"a","ccc","ddd"}; //正確,列表初始化
- 例如: vector<string> v1 = ("a","ccc","ddd"); //錯誤,不可以使用圓括號
創建指定數量的元素
- 還可以使用vector對象容納的元素數量和所有元素的統一初始值來初始化vector對象。
- vector<int> v1(10,-1);//創建10個int類型的元素,每個元素的數值都被初始化為-1
- vector<string> v2(10,"hi!");//創建10個string類型的元素,每個元素的數值都被初始化為hi!
值初始化
- 可以只提供vector對象容納的元素數量,而不提供初始數值。此時庫會創建一個值初始化的元素初值,并將其賦值給容器中所有的元素。這個初值由vector對象中的元素類型決定。
- 如果vector的對象元素類型是內置類型的,比如int,則元素初始值會被自動設置為0;如果是string類型的,則元素由類默認初始化。
限制要求
- 1,有些類必須明確的提供初始值,如果vector對象中元素的類型不支持默認初始化,就必須提供初始的元素值
- 2,如果只提供了元素的數量沒有提供元素的初始值,只能使用直接初始化。vector<int> v1 = 10;//錯誤,使用直接初始化
列表初始值還是元素的數量
-
初始化的真實含義依賴于傳遞初始值的時候使用的是花括號還是圓括號
vector<int> v1 (10); //v1有10個元素,每個元素的數值都是0vector<int> v2 {10}; //v2有1個元素,元素的數值是10vector<int> v3(10,1); //v3有10個元素,每個元素的數值都是1vector<int> v4{10,1};//v4有2個元素,元素的數值分別是10和1
向vector中添加元素
- 直接初始化常見于三種場景:1,初始值已知且數量較少;2,初始值是另外一個vector對象的副本;3,所有元素的初始值一致
- 使用函數push_back將元素添加到vectro容器的末尾,下面的例子是將100個元素押入容器中
vector<int> vInt;for(int i = 0;i !=100 ;i++){v2.push_back(i);}
- 從標準輸入中讀取單詞,將其作為vector對象的元素進行存儲
string word;vector<string> text; //空的vector對象while (cin >> word){text.push_back(word);}
- ?循環體內部包含了有向vector對象添加元素的語句,則不可以使用范圍for循環。
其他vector操作
v.empty() | 如果v不含有任何元素,返回為真;否則返回為假 |
v.size() | 返回元素的個數 |
v.push_back(t) | 向v的末尾添加一個數值為t的元素 |
v[n] | 返回v中第n個位置上元素的引用 |
v1=v2 | 用v2中的元素拷貝替換v1中的元素 |
v1={a,b,c...} | 用列表中的元素拷貝替換v1中的元素 |
v1 == v2? | v1和v2相等當且僅當元素數量相同,且對應位置上的元素值都相等 |
v1 != v2 | ? |
< <= >= > | 以字典序比較大小 |
- 訪問vector中的元素和訪問string對象中字符的方式差不多,也是通過元素在vector對象上的位置。?例如可以使用范圍for語句來處理vector中所有元素。
vector<int> v {1,2,3,4,5,6,7,8,9};for(auto &i : v){ //對于v中每個元素進行處理,其中i是一個引用i *= i;}for(auto &i : v){cout << i << " " << endl;}
第一個循環把控制變量i定義成引用類型,這樣就可以通過i給v的元素賦值
- 要使用size_type的時候,需要指定它是由哪種類型定義的。例如:vector<int>::size_type? ?//正確
計算Vector內對象的索引
- 可以通過下標運算符來獲取指定的元素;還可以通過計算得到vector內對象的索引,然后直接獲取索引位置上的元素。
- ?計算得到vector內對象的索引,舉個例子,對于輸入的成績進行歸檔,每10分一個檔次。計算方式是將其除以10就能得到對應的分數段索引,例如65/10 = 6;42/10 = 4;一旦計算得到了分數段索引,就可以把它作為vector對象的下標,進而可以獲取該分數段的計算值并加1。
// 以10分為一個分數段統計成績的數量,0~9,10~19,...,90~99,100vector<unsigned> scores(11,0); //11個分數段,全部初始化為0unsigned grade;while(cin >> grade){ //讀取成績if(grade <= 100 ){ //只處理有效的成績++scores[grade / 10]; //將對應分數段的計數值加1}if(grade == 'T'){ //輸入字符T,退出程序break;}}for(auto i : scores){ //輸出存儲的字段信息cout << i << " " << endl;}
不可以使用下標的形式添加元素
vector<int> ivec;//空的vector對象for(decltype(ivec.size()) ix = 0; ix != 10; ix++){ivec[ix] = ix;//嚴重錯誤,vector不包含任何的元素}
- 正確的方法是通過push_back的方法,將元素逐一押入容器中。
- vector對象的下標運算符可以用于訪問已經存在的元素,但是不可以用于添加元素。?
容器的特性
順序序列
- 順序容器中的元素按照嚴格的線性順序排序。可以通過元素在序列中的位置訪問對應的元素。
動態數組
能夠感知內存分配器的(Allocator-aware)
- 容器使用一個內存分配器對象來動態地處理它的存儲需求
基本函數實現
1.構造函數
- vector():創建一個空vector
- vector(int nSize):創建一個vector,元素個數為nSize
- vector(int nSize,const t& t):創建一個vector,元素個數為nSize,且值均為t
- vector(const vector&):復制構造函數
- vector(begin,end):復制[begin,end)區間內另一個數組的元素到vector中
2.增加函數
- void push_back(const T& x):向量尾部增加一個元素X
- iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一個元素x
- iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n個相同的元素x
- iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一個相同類型向量的[first,last)間的數據
3.刪除函數
- iterator erase(iterator it):刪除向量中迭代器指向元素
- iterator erase(iterator first,iterator last):刪除向量中[first,last)中元素
- void pop_back():刪除向量中最后一個元素
- void clear():清空向量中所有元素
4.遍歷函數
- reference at(int pos):返回pos位置元素的引用
- reference front():返回首元素的引用
- reference back():返回尾元素的引用
- iterator begin():返回向量頭指針,指向第一個元素
- iterator end():返回向量尾指針,指向向量最后一個元素的下一個位置
- reverse_iterator rbegin():反向迭代器,指向最后一個元素
- reverse_iterator rend():反向迭代器,指向第一個元素之前的位置
5.判斷函數
- bool empty() const:判斷向量是否為空,若為空,則向量中無元素
6.大小函數
- int size() const:返回向量中元素的個數
- int capacity() const:返回當前向量所能容納的最大元素值
- int max_size() const:返回最大可允許的vector元素數量值
7.其他函數
- void swap(vector&):交換兩個同類型向量的數據
- void assign(int n,const T& x):設置向量中第n個元素的值為x
- void assign(const_iterator first,const_iterator last):向量中[first,last)中元素設置成當前向量元素
8.補充完善
- push_back 在數組的最后添加一個數據
- pop_back 去掉數組的最后一個數據
- at 得到編號位置的數據
- begin 得到數組頭的指針
- end 得到數組的最后一個單元+1的指針
- front 得到數組頭的引用
- back 得到數組的最后一個單元的引用
- max_size 得到vector最大可以是多大
- capacity 當前vector分配的大小
- size 當前使用數據的大小
- resize 改變當前使用數據的大小,如果它比當前使用的大,則填充默認值
- reserve 改變當前vecotr所分配空間的大小
- erase 刪除指針指向的數據項
- clear 清空當前的vector
- rbegin 將vector反轉后的開始指針返回(其實就是原來的end-1)
- rend 將vector反轉構的結束指針返回(其實就是原來的begin-1)
- empty 判斷vector是否為空
- swap 與另一個vector交換數據
基本用法
-
#include < vector> using namespace std;
簡單的介紹
- Vector<類型>標識符
- Vector<類型>標識符(最大容量)
- Vector<類型>標識符(最大容量,初始所有值)
- Int i[5]={1,2,3,4,5}
Vector<類型>vi(I,i+2);//得到i索引值為3以后的值 - Vector< vector< int> >v; 二維向量//這里最外的<>要有空格。否則在比較舊的編譯器下無法通過
相關知識的引用
模板
- 模板本身不是類或者函數,相反可以把模板看做是編譯器生成類或者函數的說明。編譯器根據模板創建類或者函數的過程稱為實例化,當使用模板的時候,需要指出編譯器把類或者函數實例化成為哪種類型。
- 對于類模板來講,提供一些額外的類來指定將模板實例化成為什么樣的類。需要提供的信息是由模板來決定的,即在模板名字的后面跟上一段尖括號,在括號上放上相關的信息。
- 以vector為例,提供的額外信息是vector內所存放對象的類型
vectorr<int> ivec;//ivec保存int類型的對象
vector<Sales_item> Sales_vec;//保存Sales_item類型的對象
vector<vector<string>> file;//該向量的元素是vector對象
緩沖區溢出
- 通過下標訪問不存在的元素會導致緩沖區溢出。