轉(zhuǎn)自:https://blog.csdn.net/weixin_42430671/article/details/88631535
一、向量的介紹
向量 vector 是一種對(duì)象實(shí)體, 能夠容納許多其他類(lèi)型相同的元素, 因此又被稱為容器。與string相同, vector 同屬于STL(Standard Template Library, 標(biāo)準(zhǔn)模板庫(kù))中的一種自定義的數(shù)據(jù)類(lèi)型, 可以廣義上認(rèn)為是數(shù)組的增強(qiáng)版;
??在使用它時(shí),需要包含vector頭文件敬拓,#include< vector >;
??vector 容器與數(shù)組相比其優(yōu)點(diǎn)在于它能夠根據(jù)需要隨時(shí)自動(dòng)調(diào)整自身的大小以便容下所要放入的元素。此外, vector 也提供了許多的方法來(lái)對(duì)自身進(jìn)行操作镇草。
二、向量的聲明及初始化
vector 型變量的聲明以及初始化的形式也有許多, 常用的有以下幾種形式:
vector<int> a; //聲明一個(gè)int型的向量a;
vector<int> a(10); //聲明一個(gè)初始大小為10的向量a;
vector<int> a(10,1); //聲明一個(gè)初始大小為10且初始值都未1的向量a;
vector<int> b(a); //聲明并用向量a初始化b;
vector<int> b(a.begin(),a.begin()+3);
//聲明并將向量a的第0個(gè)到第2個(gè)(共3個(gè))作為向量b的初始值
除此之外, 還可以直接使用數(shù)組來(lái)初始化向量:
int n[] = {1, 2, 3, 4, 5};
vector<int> a(n,n+5); //將數(shù)組n的前5個(gè)元素作為向量a的初值
vector<int> a(&n[1],&n[4]); //將n[1] - n[4]范圍內(nèi)的元素作為向量a的初值
三何暇、元素的輸入及訪問(wèn)
元素的輸入和訪問(wèn)可以像操作普通的數(shù)組那樣, 用cin>>進(jìn)行輸入, cout<<a[n]這樣進(jìn)行輸出:
示例:
1 #include<iostream>
2 #include<vector>
3
4 using namespace std ;
5
6 int main()
7 {
8 vector<int> a(10, 0) ; //大小為10初值為0的向量a
9
10 //對(duì)其中部分元素進(jìn)行輸入
11 cin >>a[2] ;
12 cin >>a[5] ;
13 cin >>a[6] ;
14
15 //全部輸出
16 int i ;
17 for(i=0; i<a.size(); i++)
18 cout<<a[i]<<" " ;
19
20 return 0 ;
21 }
在元素的輸出上, 還可以使用遍歷器(又稱迭代器)進(jìn)行輸出控制陶夜。
在 vector< int > b(a.begin(), a.begin()+3);
這種聲明形式中, (a.begin()、a.begin()+3)
表示向量起始元素位置到起始元素+3之間的元素位置裆站。 (a.begin() ,a.end())
則表示起始元素和最后一個(gè)元素之外的元素位置条辟。
??向量元素的位置便成為遍歷器, 同時(shí), 向量元素的位置也是一種數(shù)據(jù)類(lèi)型, 在向量中遍歷器的類(lèi)型為: vector< int >::iterator黔夭。 遍歷器不但表示元素位置, 還可以再容器中前后移動(dòng)。
??在上例中講元素全部輸出部分的代碼就可以改寫(xiě)為:
//全部輸出
vector<int>::iterator t ;
for(t=a.begin(); t!=a.end(); t++)
cout<<*t<<" " ;
*t 為指針的間接訪問(wèn)形式, 意思是訪問(wèn)t所指向的元素值羽嫡。
四本姥、向量的基本操作
- a.size() //獲取向量中的元素個(gè)數(shù);
- a.empty() //判斷向量是否為空杭棵;
- a.clear() //清空向量中的元素婚惫;
- a=b //將b向量復(fù)制到a向量中;
- 如a==b //a向量與b向量比較, 相等則返回1;
- 插入 - insert
①a.insert(a.begin(),1000); //將1000插入到向量a的起始位置前;
②a.insert(a.begin(),3,1000) ; //將1000分別插入到向量元素位置的0-2處魂爪;
③vector<int> a(5, 1) ;
vector<int> b(10) ;
b.insert(b.begin(),a.begin(),a.end()) ;
//將a.begin(),a.end()之間的全部元素插入到b.begin()前- 刪除 - erase
①b.erase(b.begin()) ; //將起始位置的元素刪除;
②b.erase(b.begin(),b.begin()+3); //將(b.begin(), b.begin()+3)之間的元素刪除;- b.swap(a) ; //a向量與b向量進(jìn)行交換
五先舷、二維向量
與數(shù)組相同, 向量也可以增加維數(shù), 例如聲明一個(gè)m*n大小的二維向量方式可以像如下形式:
vector< vector<int> > b(10, vector<int>(5)); //創(chuàng)建一個(gè)10*5的int型二維向量
在這里, 實(shí)際上創(chuàng)建的是一個(gè)向量中元素為向量的向量。同樣可以根據(jù)一維向量的相關(guān)特性對(duì)二維向量進(jìn)行操作滓侍。
例:
1 #include<iostream>
2 #include<vector>
3
4 using namespace std ;
5
6 int main()
7 {
8 vector< vector<int> > b(10, vector<int>(5, 0)) ;
9
10 //對(duì)部分?jǐn)?shù)據(jù)進(jìn)行輸入
11 cin>>b[1][1] ;
12 cin>>b[2][2] ;
13 cin>>b[3][3];
14
15 //全部輸出
16 int m, n ;
17 for(m=0; m<b.size(); m++) //b.size()獲取行向量的大小
18 {
19 for(n=0; n<b[m].size(); n++) //獲取向量中具體每個(gè)向量的大小
20 cout<<b[m][n]<<" " ;
21 cout<<"\n" ;
22 }
23
24 return 0;
25 }
同樣, 按照這樣的思路我們還可以創(chuàng)建更多維的向量, 不過(guò)維數(shù)太多會(huì)讓向量變得難以靈活控制, 三維以上的向量還需酌情使用蒋川。
1. 在C++中的詳細(xì)說(shuō)明
vector是C++標(biāo)準(zhǔn)模板庫(kù)中的部分內(nèi)容,它是一個(gè)多功能的撩笆,能夠操作多種數(shù)據(jù)結(jié)構(gòu)和算法的模板類(lèi)和函數(shù)庫(kù)捺球。
??vector之所以被認(rèn)為是一個(gè)容器,是因?yàn)樗軌蛳袢萜饕粯哟娣鸥鞣N類(lèi)型的對(duì)象夕冲,
??簡(jiǎn)單地說(shuō)氮兵,vector是一個(gè)能夠存放任意類(lèi)型的動(dòng)態(tài)數(shù)組,能夠增加和壓縮數(shù)據(jù)歹鱼。
2. 使用vector
必須在你的頭文件中包含下面的代碼:
#include
vector屬于std命名域的泣栈,因此需要通過(guò)命名限定,如下完成你的代碼:
using std::vector;
vector vInts;
或者連在一起醉冤,使用全名:
std::vector vInts;
建議使用全局的命名域方式:
using namespace std;
- 初始化
vector // 創(chuàng)建一個(gè)空的vector秩霍。
vector c1(c2) // 復(fù)制一個(gè)vector
vector c(n) // 創(chuàng)建一個(gè)vector,含有n個(gè)數(shù)據(jù)蚁阳,數(shù)據(jù)均已缺省構(gòu)造產(chǎn)生
vector c(n, elem) // 創(chuàng)建一個(gè)含有n個(gè)elem拷貝的vector
vector c(beg,end) // 創(chuàng)建一個(gè)含有n個(gè)elem拷貝的vector
- 析構(gòu)函數(shù)
5. 成員函數(shù)
c.assign(beg,end)c.assign(n,elem)
將[beg; end)區(qū)間中的數(shù)據(jù)賦值給c铃绒。將n個(gè)elem的拷貝賦值給c。
??c.at(idx)
傳回索引idx所指的數(shù)據(jù)螺捐,如果idx越界颠悬,拋出out_of_range。
c.back() // 傳回最后一個(gè)數(shù)據(jù)定血,不檢查這個(gè)數(shù)據(jù)是否存在赔癌。
c.begin() // 傳回迭代器中的第一個(gè)數(shù)據(jù)地址。
c.capacity() // 返回容器中數(shù)據(jù)個(gè)數(shù)澜沟。
c.clear() // 移除容器中所有數(shù)據(jù)灾票。
c.empty() // 判斷容器是否為空。
c.end() // 指向迭代器中末端元素的下一個(gè)茫虽,指向一個(gè)不存在元素刊苍。
c.erase(pos) // 刪除pos位置的數(shù)據(jù)既们,傳回下一個(gè)數(shù)據(jù)的位置。
c.erase(beg,end) //刪除[beg,end)區(qū)間的數(shù)據(jù)正什,傳回下一個(gè)數(shù)據(jù)的位置啥纸。
c.front() // 傳回第一個(gè)數(shù)據(jù)。
get_allocator // 使用構(gòu)造函數(shù)返回一個(gè)拷貝婴氮。
c.insert(pos,elem) // 在pos位置插入一個(gè)elem拷貝斯棒,傳回新數(shù)據(jù)位置。
c.insert(pos,n,elem) // 在pos位置插入n個(gè)elem數(shù)據(jù)主经。無(wú)返回值荣暮。
c.insert(pos,beg,end) // 在pos位置插入在[beg,end)區(qū)間的數(shù)據(jù)。無(wú)返回值旨怠。
c.max_size() // 返回容器中最大數(shù)據(jù)的數(shù)量渠驼。
c.pop_back() // 刪除最后一個(gè)數(shù)據(jù)。
c.push_back(elem) // 在尾部加入一個(gè)數(shù)據(jù)鉴腻。
c.rbegin() // 傳回一個(gè)逆向隊(duì)列的第一個(gè)數(shù)據(jù)。
c.rend() // 傳回一個(gè)逆向隊(duì)列的最后一個(gè)數(shù)據(jù)的下一個(gè)位置百揭。
c.resize(num) // 重新指定隊(duì)列的長(zhǎng)度爽哎。
c.reserve() // 保留適當(dāng)?shù)娜萘俊? c.size() // 返回容器中實(shí)際數(shù)據(jù)的個(gè)數(shù)。
c1.swap(c2)
swap(c1,c2) // 將c1和c2元素互換器一。同上操作课锌。
operator[] // 返回容器中指定位置的一個(gè)引用享潜。
6. 用法示例:
6.1. 創(chuàng)建一個(gè)vector
vector容器提供了多種創(chuàng)建方法宝当,下面介紹幾種常用的睬罗。
創(chuàng)建一個(gè)Widget類(lèi)型的空的vector對(duì)象:
vector vWidgets;
創(chuàng)建一個(gè)包含500個(gè)Widget類(lèi)型數(shù)據(jù)的vector:
vector vWidgets(500);
創(chuàng)建一個(gè)包含500個(gè)Widget類(lèi)型數(shù)據(jù)的vector酿矢,并且都初始化為0:
vector vWidgets(500, Widget(0));
創(chuàng)建一個(gè)Widget的拷貝:
vector vWidgetsFromAnother(vWidgets);
向vector添加一個(gè)數(shù)據(jù):
vector添加數(shù)據(jù)的缺省方法是push_back()姑荷。
?push_back()函數(shù)表示將數(shù)據(jù)添加到vector的尾部伟葫,并按需要來(lái)分配內(nèi)存鼓蜒。
?例如:向vector中添加10個(gè)數(shù)據(jù)家乘,需要如下編寫(xiě)代碼:
for(int i= 0;i<10; i++) {
vWidgets.push_back(Widget(i));
}
6.2 獲取vector中指定位置的數(shù)據(jù)
vector里面的數(shù)據(jù)是動(dòng)態(tài)分配的方仿,使用push_back()的一系列分配空間常常決定于文件或一些數(shù)據(jù)源固棚。
如果想知道vector存放了多少數(shù)據(jù),可以使用empty()仙蚜。
獲取vector的大小此洲,可以使用size()。
例如委粉,如果想獲取一個(gè)vector v的大小呜师,但不知道它是否為空,或者已經(jīng)包含了數(shù)據(jù)贾节,如果為空想設(shè)置為-1汁汗,
你可以使用下面的代碼實(shí)現(xiàn):
int nSize = v.empty() ? -1 : static_cast(v.size());
6.3 訪問(wèn)vector中的數(shù)據(jù)
使用兩種方法來(lái)訪問(wèn)vector趟紊。
1 vector::at()
2 vector::operator[]
operator[]主要是為了與C語(yǔ)言進(jìn)行兼容。它可以像C語(yǔ)言數(shù)組一樣操作碰酝。
但at()是我們的首選霎匈,因?yàn)閍t()進(jìn)行了邊界檢查,如果訪問(wèn)超過(guò)了vector的范圍送爸,將拋出一個(gè)例外铛嘱。
由于operator[]容易造成一些錯(cuò)誤,所有我們很少用它袭厂,下面進(jìn)行驗(yàn)證一下:
分析下面的代碼:
vector v;
v.reserve(10);
for(int i=0; i<7; i++) {
v.push_back(i);
}
try {int iVal1 = v[7];
// not bounds checked - will not throw
int iVal2 = v.at(7);
// bounds checked - will throw if out of range
}
catch(const exception& e) {
cout << e.what();
}
6.3 刪除vector中的數(shù)據(jù)
vector能夠非常容易地添加數(shù)據(jù)墨吓,也能很方便地取出數(shù)據(jù),
同樣vector提供了erase()纹磺,pop_back()帖烘,clear()來(lái)刪除數(shù)據(jù),
當(dāng)刪除數(shù)據(jù)時(shí)橄杨,應(yīng)該知道要?jiǎng)h除尾部的數(shù)據(jù)秘症,或者是刪除所有數(shù)據(jù),還是個(gè)別的數(shù)據(jù)式矫。
Remove_if()算法:如果要使用remove_if()乡摹,需要在頭文件中包含如下代碼:
#include
Remove_if()有三個(gè)參數(shù):
1 iterator _First:指向第一個(gè)數(shù)據(jù)的迭代指針〔勺
2 iterator _Last:指向最后一個(gè)數(shù)據(jù)的迭代指針聪廉。
3 predicate _Pred:一個(gè)可以對(duì)迭代操作的條件函數(shù)。
6.4 條件函數(shù)
條件函數(shù)是一個(gè)按照用戶定義的條件返回是或否的結(jié)果故慈,是最基本的函數(shù)指針板熊,或是一個(gè)函數(shù)對(duì)象。
這個(gè)函數(shù)對(duì)象需要支持所有的函數(shù)調(diào)用操作察绷,重載operator()操作干签。
remove_if()是通過(guò)unary_function繼承下來(lái)的,允許傳遞數(shù)據(jù)作為條件克婶。
例如筒严,假如想從一個(gè)vector中刪除匹配的數(shù)據(jù),如果字串中包含了一個(gè)值情萤,從這個(gè)值開(kāi)始鸭蛙,從這個(gè)值結(jié)束。
首先應(yīng)該建立一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)包含這些數(shù)據(jù)筋岛,類(lèi)似代碼如下:
#include
enum findmodes {
FM_INVALID = 0,
FM_IS,
FM_STARTSWITH,
FM_ENDSWITH,
FM_CONTAINS
};
typedef struct tagFindStr {
UINT iMode;
CString szMatchStr;
} FindStr;
typedef FindStr* LPFINDSTR;
然后處理?xiàng)l件判斷:
class FindMatchingString : public std::unary_function<cstring, bool=""> {
public:
FindMatchingString(const LPFINDSTR lpFS) :
m_lpFS(lpFS) {}
bool operator()(CString& szStringToCompare) const {
bool retVal = false;
switch (m_lpFS->iMode) {
case FM_IS: {
retVal = (szStringToCompare == m_lpFDD->szMatchStr);
break;
}
case FM_STARTSWITH: {
retVal = (szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength())
== m_lpFDD->szWindowTitle);
break;
}
case FM_ENDSWITH: {
retVal = (szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength())
== m_lpFDD->szMatchStr);
break;
}
case FM_CONTAINS: {
retVal = (szStringToCompare.Find(m_lpFDD->szMatchStr) != -1);
break;
}
}
return retVal;
}
private:
LPFINDSTR m_lpFS;
};
通過(guò)這個(gè)操作你可以從vector中有效地刪除數(shù)據(jù):
FindStr fs;
fs.iMode = FM_CONTAINS;
fs.szMatchStr = szRemove;
vs.erase(std::remove_if(vs.begin(), vs.end(), FindMatchingString(&fs)), vs.end());
Remove(),remove_if()等所有的移出操作都是建立在一個(gè)迭代范圍上的娶视,不能操作容器中的數(shù)據(jù)。
所以在使用remove_if(),實(shí)際上操作的時(shí)容器里數(shù)據(jù)的上面的肪获。
看到remove_if()實(shí)際上是根據(jù)條件對(duì)迭代地址進(jìn)行了修改寝凌,在數(shù)據(jù)的后面存在一些殘余的數(shù)據(jù),
那些需要?jiǎng)h除的數(shù)據(jù)孝赫。剩下的數(shù)據(jù)的位置可能不是原來(lái)的數(shù)據(jù)较木,但他們是不知道的。
調(diào)用erase()來(lái)刪除那些殘余的數(shù)據(jù)青柄。
注意上面例子中通過(guò)erase()刪除remove_if()的結(jié)果和vs.enc()范圍的數(shù)據(jù)伐债。
7. 綜合例子:
//---------------------------------------------------------------------------
#include
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
#include
#include
using namespace std;
struct STResult
{
double Time;
double Xp;
double Yp;
int id;
};
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
vector ResultVector;
void __fastcall test()
{
//test
//vector ResultVector;
STResult stritem;
stritem.Time = .1;
stritem.Xp = .1;
stritem.Yp = .1;
stritem.id = 1;
ResultVector.push_back( stritem );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
test();
assert(ResultVector[0].id == 1);
}