C++ vector型別要點總結【轉】
(轉自:https://blog.csdn.net/suool/article/details/13295439?utm_source=blogxgwz22)
概述
C++內建的陣列支援容器的機制,但是它不支援容器抽象的語義。要解決此問題我們自己實現這樣的類。在標準C++中,用容器向量(vector)實現。
容器向量也是一個類模板。vector是C++標準模板庫中的部分內容,它是一個多功能的,能夠操作多種資料結構和演算法的模板類和函式庫。vector之所以被認為是一個容器,是因為它能夠像容器一樣存放各種型別的物件,但是一個容器中的物件必須是同一種類型。簡單地說,vector是一個能夠存放任意型別的動態陣列,能夠增加和壓縮資料。
vector是一個類模板,不是一種資料型別。可用來定義任意多種資料型別。vector型別的每一種都指定了其儲存元素的型別。因此vector <int >等都是資料型別。
vector物件初始化
vector 類定義了好幾種構 造函式,用來定義和初始化 vector 物件。
初始化 vector 物件的方式
vector <T > v1 ; vector 儲存型別為 T 的物件。預設建構函式 v1 為空。
vector < T > v2 ( v1 ); v2 是 v1 的一個副本。
vector < T > v3 ( n , i ); v3 包含 n 個值為 i 的元素。
vector < T > v4 ( n ); v4 含有值初始化的元素的 n 個副本。
建立確定個數的元素
若要建立非空的 vector 物件,必須給出初始化元素的值。當把一個 vector 物件複製到另一個 vector 物件時,新複製的 vector 中每一個元素都初始化為原 vector 中相應元素的副本。但這兩個 vector 物件必須儲存同一種元素型別:
vector<int> ivec1; // ivec1 holds objects of type int vector<int> ivec2(ivec1); // ok: copy elements of ivec1 into ivec2 vector<string> svec(ivec1); // error: svec holds strings, not ints
可以用元素個數和元素值對 vector 物件進行初始化。建構函式用元素個數來決定 vector 物件儲存元素的個數,元素值指定每個元素的初始值:
vector<int> ivec4(10, -1); // 10 elements, each initialized to -1
vector<string> svec(10, "hi!"); // 10 strings, each initialized to "hi!"
值初始化
如果沒有給出元素的初始化式,那麼標準庫將提供一個 值初始化的 ( value initialized )元素初始化式。這個由庫生成的初始值用於初始化容器中的每個元素。而元素初始化式的值取決於儲存在 vector 中元素的資料型別。
如果 vector 儲存內建型別(如 int 型別) 的元素,那麼標準庫將用 0 值建立元素初始 化值:
vector<string> fvec(10); // 10 elements, each initialized to 0
如果向量儲存類型別(如 string )的元素,標準庫將用該型別的預設建構函式 建立 元素初始值:
vector<string> svec(10); // 10 elements, each an empty string
vector物件操作
vector 基本操作
v. empty() 如果 v 為空,則返回 true, 否則返回 false 。
v . size () 返回 v 中元素的個數。
v . push _ back ( t ) 在 v 的末尾增加一個值為 t 的元素。
v [ n ] 返回 v 中位置為 n 的元素。
v1 = v2 把 v1 的元素替換為 v2 中元素的副本。
v1 == v2 如果 v1 與 v2 相等,則返回 true 。
!=, <, <=, >, >= 保持這些操作符慣有的含義。
vector 物件的 size
empty 和 size 操作類似於 string 型別的相關操作。成員函式 size 返回相應 vector 類定義的size_type 的值。
使用 size_type 型別時,必須指出該型別是在哪裡定義的。 vector 型別總是 包括 vector 的元素型別:
vector<int>::size_type // ok
vector::size_type // error
向 vector 新增元素
push_back() 操作接受一個元素值,並將它作為一個新的元素新增到 vector 物件的後面,也就是“ 插入 ( push)” 到 vector 物件的 “ 後面 ( back ) ” :
// read words from the standard input and store them as elements in a vector
string word;
vector<string> text; // empty vector
while (cin >> word) {
text.push_back(word); // append word to text
}
該迴圈從標準輸入讀取一系列 string 物件,逐一追加到 vector 物件的後面。首先定義一個空的 vector 物件 text 。每迴圈一次就新增一個新元素到 vector 物件,並將從 輸入 讀取的 word 值賦予該元素。當迴圈結束時, text 就包含了所有讀入的元素。
vector 的下標操作(更推薦用迭代器)
vector 中的物件是沒有命名的,可以按 vector 中物件的位置來訪問它們。通常使用下標操作符來獲取元素。 vector的下標操作類似於 string 型別的下標操作 ( 3 .2 .3 節 ) 。
vector 的下標操作符接受一個值,並返回 vector 中該對應位置的元素。 vector 元素的位置從 0 開始。下例使用 for迴圈把 vector 中的每個元素值都重置為 0 :
// reset the elements in the vector to zero
for (vector<int>::size_type ix = 0; ix != ivec.size(); ++ix)
ivec[ix] = 0;
和 string 型別的下標操作符一樣, vector 下標操作的結果為左值,因此可以像迴圈體中所做的那樣實現寫入。另外,和 string 物件的下標操作類似,這裡用 size_type 型別作為 vector 下標的型別。
在上例中,即使 ivec 為空, for 迴圈也會正確執行。 ivec 為空則呼叫 size 返回 0 ,並且 for 中的測試比較 ix 和 0 。第一次迴圈時,由於 ix 本身就是 0 ,則條件測試失敗, for 迴圈體一次也不執行。
僅能對確知已存在的元素進行下標操作
初學 C ++ 的程式設計師可能會認為 vector 的下標操作可以新增元素,其實不然:
vector<int> ivec; // empty vector
for (vector<int>::size_type ix = 0; ix != 10; ++ix)
ivec[ix] = ix; // disaster: ivec has no elements
上述程式試圖在 ivec 中插入 10 個新元素,元素值依次為 0 到 9 的整數。但是,這裡 ivec 是空的 vector 物件,而且下標只能用於獲取已存在的元素。
這個迴圈的正確寫法應該是:
for (vector<int>::size_type ix = 0; ix != 10; ++ix)
ivec.push_back(ix); // ok: adds new element with value ix
必須是已存在的元素才能用下標操作符進行索引。通過下標操作進行賦值時,不會新增任何元素。
對於下標操作符 ( [] 操作符 ) 的使用有一點非常重要,就是僅能提取確實已存在的元素,例如:
vector<int> ivec; // empty vector
cout << ivec[0]; // Error: ivec has no elements!
vector<int> ivec2(10); // vector with 10 elements
cout << ivec[10]; // Error: ivec has elements 0...9
試圖獲取不存在的元素必然產生執行時錯誤。和大多數同類錯誤一樣,不能確保執行過程可以捕捉到這類錯誤,執行程式的結果是不確定的。由於取不存在的元素的結果是未定義的,因而不同的實現會導致不同的結果,但程式執行時幾乎肯定會以某種有趣的方式失敗。
本警告適用於任何使用下標操作的時候,如 string 型別的下標操作,以及將要簡要介紹的內建陣列的下標操作。
不幸的是,試圖對不存在的元素進行下標操作是程式設計過程中經常會犯的嚴重錯誤。所謂的“緩衝區溢位”錯誤就是對不存在的元素進行下標操作的結果。這樣的缺陷往往導致 PC 機和其他應用中最常見的安全問題。
其他以及迭代器
① v.resize(2*v.size)或v.resize(2*v.size, 99) 將v的容量翻倍(並把新元素的值初始化為99)
②使用迭代器訪問元素.
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
③ c.insert(pos,elem) // 在pos位置插入一個elem拷貝,傳回新資料位置。
c.insert(pos,n,elem) // 在pos位置插入n個elem資料。無返回值。
c.insert(pos,beg,end) // 在pos位置插入在[beg,end)區間的資料。無返回值。
vec.insert(vec.begin()+i,a); 在第i+1個元素前面插入a;
④ c.erase(pos) 刪除pos位置的資料,傳回下一個資料的位置。
c.erase(beg,end) 刪除[beg,end)區間的資料,傳回下一個資料的位置。
⑤ c.assign(beg,end) 將[beg; end)區間中的資料賦值給c
c.assign(n,elem) 將n個elem的拷貝賦值給c。
⑥ c.at(idx) 傳回索引idx所指的資料,如果idx越界,丟擲out_of_range。
⑦ c.back() 傳回最後一個數據,不檢查這個資料是否存在。
⑧ c.begin()傳回迭代器中的第一個資料
c.clear()移除容器中所有資料。
c.empty()判斷容器是否為空。
c.end()指向迭代器中末端元素的下一個,指向一個不存在元素。
More:vector結構體
vector的元素不僅僅可以使int,double,string,還可以是結構體,但是要注意:結構體要定義為全域性的,否則會出錯。下面是一段簡短的程式程式碼:
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef struct rect
{
int id;
int length;
int width;
//對於向量元素是結構體的,可在結構體內部定義比較函式,下面按照id,length,width升序排序。
bool operator< (const rect &a) const
{
if(id!=a.id)
return id<a.id;
else
{
if(length!=a.length)
return length<a.length;
else
return width<a.width;
}
}
}Rect;
int main()
{
vector<Rect> vec;
Rect rect;
rect.id=1;
rect.length=2;
rect.width=3;
vec.push_back(rect);
vector<Rect>::iterator it=vec.begin();
cout<<(*it).id<<' '<<(*it).length<<' '<<(*it).width<<endl;
return 0;
}
演算法:
#include<algorithm>中的泛函演算法
搜尋演算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if()
分類排序:sort() 、merge()
刪除演算法:unique() 、remove()
生成和變異:generate() 、fill() 、transformation() 、copy()
關係演算法:equal() 、min() 、max()
sort(v1.begin(),vi.begin()+v1.size/2); 對v1的前半段元素排序
list<char>::iterator pMiddle =find(cList.begin(),cList.end(),'A');找到則返回被查內容第一次出現處指標,否則返回end()。
vector< typeName >::size_type x ; vector< typeName >型別的計數,可用於迴圈如同for(int i)
使用reverse將元素翻轉
reverse(vec.begin(),vec.end());將元素翻轉(在vector中,如果一個函式中需要兩個迭代器,
一般後一個都不包含.)
使用sort排序
sort(vec.begin(),vec.end());(預設是按升序排列,即從小到大).
可以通過重寫排序比較函式按照降序比較,如下:
定義排序比較函式:
bool Comp(const int &a,const int &b)
{
return a>b;
}
呼叫時:sort(vec.begin(),vec.end(),Comp),這樣就降序排序。
/*
vector 綜合練習
Written by C_SuooL_Hu
2013 10 29
*/
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std ;
int main()
{
// 四種初始化方式
vector<int> ivec_1;
vector<int> ivec_2(ivec_1);
vector<int> ivec_3(10, 0) ;
vector<int> ivec(10);
// 定義迭代器變數
vector<int>::iterator iter;
// 定義下標變數
vector<int>::size_type ix ;
system("echo off");
system("color 3") ;
// reset all the elements in ivec to 0
// 使用下標操作,重置為1
for (ix = 0; ix != ivec.size(); ++ix)
ivec[ix] = 1;
// print what we've got so far: should print 10 0's
cout << "使用下標賦值為1的vector<int>型別(同樣用下標遍歷輸出):"<< endl;
for (ix = 0; ix != ivec.size(); ++ix)
cout << ivec[ix] << " ";
cout << endl;
// 使用迭代器的操作賦值,重置為0
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
*iter = 0;
// 遍歷輸出,使用迭代器
cout<<"使用迭代器賦值為0的vector<int>型別(同樣用迭代器遍歷輸出):" << endl;
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
cout<< *iter << ' ' ;
cout<< endl ;
iter = ivec.begin();
while (iter != ivec.end())
{
*iter =2 ;
++iter;
}
// 遍歷輸出,使用迭代器
cout<<"使用while迴圈的迭代器賦值為2的數列的vector<int>型別(同樣用迭代器遍歷輸出):" << endl;
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
cout<< *iter << ' ' ;
cout<< endl << endl ;
// 使用vector的成員函式操作vector<int>型別資料
// 新增元素
cout << "使用vector的成員函式操作vector<int>型別資料" << endl;
cout << "新增元素" << endl ;
cout << "使用迭代器,新增九個遞增元素" << endl ;
for (ix = 0; ix != 10; ++ ix)
ivec.push_back(ix);
cout << "此時ivec共有" << ivec.size() << "個元素"<< endl;
// 遍歷輸出,使用迭代器
cout<<"使用下標增加元素為遞增的的數列的vector<int>型別(同樣用迭代器遍歷輸出):" << endl;
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
cout<< *iter << ' ' ;
cout<< endl << endl;
// 插入元素
cout << "插入元素:在第二個位置插入一個43" << endl ;
ivec.insert(ivec.begin() + 1, 43); // 在2位置插入一個43拷貝,傳回新資料位置。
// 遍歷輸出,使用迭代器
cout<<"使用迭代器遍歷輸出:" << endl;
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
cout<< *iter << ' ' ;
cout << "\n此時ivec共有" << ivec.size() << "個元素" ;
cout<< endl << endl ;
cout << "插入元素:在第一個位置插入三個13" << endl ;
ivec.insert(ivec.begin(), 3 , 13); // 在1位置插入3個13資料。無返回值。
// 遍歷輸出,使用迭代器
cout<<"使用迭代器遍歷輸出:" << endl;
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
cout<< *iter << ' ' ;
cout << "\n此時ivec共有" << ivec.size() << "個元素";
cout<< endl << endl ;
cout << "插入元素:在第7個位置插入ivec的[1, 6) 之間的資料:" << endl ;
ivec.insert(ivec.begin()+6, ivec.begin(), ivec.begin()+5); // 在7位置插入在[10,19)區間的資料。無返回
// 遍歷輸出,使用迭代器
cout<<"使用迭代器遍歷輸出:" << endl;
for (iter = ivec.begin(); iter !=ivec.end(); ++iter )
cout<< *iter << ' ' ;
cout << "\n此時ivec共有" << ivec.size() << "個元素";
cout<< endl << endl ;
cout << "使用assign賦值ivec_1(將ivec的第[10,19)個元素賦值給他):" <<endl ;
ivec_1.assign(ivec.begin()+9, ivec.begin()+18);
cout<<"使用迭代器遍歷輸出:" << endl;
for (iter = ivec_1.begin(); iter !=ivec_1.end(); ++iter )
cout<< *iter << ' ' ;
cout << "\n此時ivec_1共有" << ivec_1.size() << "個元素";
cout << endl;
cout << "使用assign賦值ivec_2:" <<endl ;
ivec_2.assign(10,8) ;
cout<<"使用迭代器遍歷輸出:" << endl;
for (iter = ivec_2.begin(); iter !=ivec_2.end(); ++iter )
cout<< *iter << ' ' ;
cout << "\n此時ivec_2共有" << ivec_2.size() << "個元素";
cout << endl;
// 元素排序
/*
由於vc 6.0對模板庫支援不夠好,這裡的排序函式無法通過編譯,但是使用vs2010編譯通過。
cout << "對ivec排序:" << endl;
bool Comp(const int &a,const int &b)
{
return a>b;
}
sort (ivec.begin(), ivec.end,Comp);
cout<<"從大到小排序後,使用迭代器遍歷輸出:" << endl;
for (iter = ivec_2.begin(); iter !=ivec_2.end(); ++iter )
cout<< *iter << ' ' ;
*/
cout << "是否為空(0代表不是,1代表是):" << ivec.empty() << endl;
ivec.clear() ;
cout << "清空元素" << endl;
cout << "是否為空:" << ivec.empty() << endl;
return 0;
}
執行結果: