3.3.2 vector的查增删
1.?vector的初始化和遍历
vector的初始化方法如表3-1所示。
表3-1 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) v4包含了n个重复地执行了值初始化的对象
vector<T>
v5{a,b,c...} v5包含了初始值个数的元素,每个元素被赋予相应的初始值
vector<T>
v5={a,b,c...} 等价于v5{a,b,c...}
vector的遍历有for(int i=0;i<a.size();++i)、for
(iter=ivector.begin();iter!=ivector.end();iter++)、for_each这几种方式。
【例3.8】 vector的初始化和遍历。
#include
<vector>
#include
<iostream>
using namespace
std;
int main(){
int a[7]={1,2,3,4,5,6,7};
vector<int> ivector(a,a+7);
/*vector的赋值并不可以像数组一样用花括号方便地完成赋值,这里借用了数组来初始化这个vector
初始化方式vector<elementType> intvec(begin,end);这样可以用起来看上去还是比较习惯的。*/
vector<int>::iterator iter;
for
(iter=ivector.begin();iter!=ivector.end();iter++){
cout<<*iter<<" ";
}
cout<<endl;
ivector[5]=1;
/*单个vector的赋值,这个方式看上去还是和数组一样的也可以这么写ivector.at(5)=1;但是
就是不习惯*/
cout<<ivector[5]<<endl<<ivector.size()<<endl;
for
(iter=ivector.begin();iter!=ivector.end();iter++){
cout<<*iter<<" ";
}
cout<<endl;
for(int i=0;i<5;i++){
cout<<ivector[i]<<"
";
}
cout<<endl;
return 0;
}
程序的执行结果是:
1 2 3 4 5 6 7
1
7
1 2 3 4 5 1 7
1 2 3 4 5
例3.8中展示了for(int
i=0;i<a.size();++i)、for (iter=ivector.begin();iter!=ivector.end();iter++)的遍历方式,vector中也可以直接用ivector[i]的方式访问第i个元素。
【例3.9】 for_each的遍历举例。
#include
<vector>
#include
<algorithm>
#include
<iostream>
using namespace
std;
void print(int
n)
{
cout<<n<<" ";
}
int main(){
int a[7]={1,2,3,4,5,6,7};
vector<int> ivector(a,a+7);
vector<int>::iterator iter;
for_each(ivector.begin(),ivector.end(),print);// 用for_each进行遍历
cout<<endl;
ivector[5]=1;
cout<<ivector[5]<<endl<<ivector.size()<<endl;
for_each(ivector.begin(),ivector.end(),print);// 用for_each进行遍历
return 0;
}
程序的执行结果为:
1 2 3 4 5 6 7
1
7
1 2 3 4 5 1 7
例3.9中展示了如何使用for_each遍历vector中的元素。
vector是个模板类,可以存放任何类型的对象。在vector中存放结构体时,可以按照自定义的排序方式排序。
【例3.10】 vector中存放结构体时的排序。
#include<algorithm>
#include<vector>
#include<iostream>
using namespace
std;
typedef struct
rect{
int id;
int length;
int 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=2;
rect.length=3;
rect.width=4;
vec.push_back(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;
sort(vec.begin(),vec.end());
cout<<(*it).id<<'
'<<(*it).length<<' '<<(*it).width<<endl;
return 0;
}
程序的执行结果是:
2 3 4
1 2 3
例3.10中,vec中存放的是结构体Rect。vec未进行排序前,将会按照push_back的时间顺序排序,并不会自动排序。排序后,可以按照结构体中对rect的重载方式进行排序:按照id、length、width升序排序,然后用<algorithm>中的sort函数排序。
除了重载结构体里的rect,也可以在结构体外定义一个函数来进行比较。
【例3.11】 结构体外定义比较函数。
#include<algorithm>
#include<vector>
#include<iostream>
using namespace
std;
typedef struct
rect{
int id;
int length;
int width;
}Rect;
int cmp(Rect
a,Rect b){
if(a.id!=b.id)
return a.id<b.id;
else{
if(a.length!=b.length)
return a.length<b.length;
else
return a.width<b.width;
}
}
int main(){
vector<Rect> vec;
Rect rect;
rect.id=2;
rect.length=3;
rect.width=4;
vec.push_back(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;
sort(vec.begin(),vec.end(),cmp);
cout<<(*it).id<<'
'<<(*it).length<<' '<<(*it).width<<endl;
return 0;
}
程序的执行结果是:
2 3 4
1 2 3
例3.11与例3.10不同的地方是,例3.11中并没有对结构体进行重载,而是在结构体外定义了一个比较函数;另外sort的调用方式也不相同,例3.11中加了个比较函数作为第3个参数。二者均可以实现对vec的排序。
2.?vector的查找
在vector中查找一个元素可以如例3.12所示。
【例3.12】 在vector中查找元素。
#include<algorithm>
#include<vector>
#include<iostream>
using namespace
std;
int main(){
vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
vector<int>::iterator
iter=find(vec.begin(),vec.end(),3);
if ( iter==vec.end())
cout << "Not found"
<< endl;
else
cout << "Found"
<< endl;
return 0;
}
程序的执行结果是:
Found
例3.12中,使用了f?ind函数在vector中进行查找。注意f?ind函数不属于vector的成员,而存在于算法中,所以应加上头文件#include <algorithm>。
3.?vector的删除
vector中的删除,可以有erase或pop_back函数。erase可以删除指定元素或指定位置的元素,而pop_back只能去掉数组的最后一个数据。
erase的函数原型有以下两种形式:
iterator
erase(iterator position)。
iterator
erase(iterator first, iterator last)。
假设有这样的程序:
vector<int>
vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
for(vector<int>::iterator
iter=veci.begin(); iter!=veci.end(); iter++){
if( *iter == 3)
veci.erase(iter);
}
乍一看这段代码很正常,其实这里面隐藏着一个很严重的错误:当veci.erase(iter)语句执行了之后,iter就变成了一个野指针,对一个野指针进行iter++操作是肯定会出错的。
查看MSDN,对于erase的返回值是这样描述的:An iterator that designates the
f?irst element remaining beyond any elements removed, or a pointer to the end
of the vector if no such element exists,于是改代码:
for(vector<int>::iterator
iter=vec.begin(); iter!=vec.end(); iter++){
if( *iter == 3)
iter = vec.erase(iter);
}
这段代码也是错误的:①无法删除两个连续的3;②当数字3位于vector最后位置的时候,也会出错(在vec.end()上执行++操作)。正确的代码应如例3.13所示。
【例3.13】 使用erase删除vector中某个元素。
#include<algorithm>
#include<vector>
#include<iostream>
using namespace
std;
int main(){
vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
vector<int>::iterator
iter=vec.begin();
for(;iter!=vec.end();){
if(*iter==3){
iter=vec.erase(iter);
}else{
++iter;
}
}
for(iter=vec.begin();iter!=vec.end();iter++){
cout<<*iter<<"
";
}
return 0;
}
程序的执行结果是:
1 2 4 5
例3.13中,for语句条件里面删除元素时,返回值指向已删除元素的下一个位置,不是删除元素时则直接进行++操作。
使用vec.erase(vec.begin()+i,vec.end()+j)语句则是删除区间[i,j-1]间的元素。
而pop_back只能去掉数组的最后一个数据。
【例3.14】 vector的pop_back函数使用举例。
#include<algorithm>
#include<vector>
#include<iostream>
using namespace
std;
int main(){
vector<int> vec;
for(int i=0;i<10;i++)
vec.push_back(i);
vector<int>::iterator
iter=vec.begin();
for(iter=vec.begin();iter!=vec.end();iter++){
cout<<*iter<<" ";
}
cout<<endl;
vec.pop_back();
for(iter=vec.begin();iter!=vec.end();iter++){
cout<<*iter<<" ";
}
cout<<endl;
return 0;
}
程序的执行结果是:
0 1 2 3 4 5 6 7
8 9
0 1 2 3 4 5 6 7
8
例3.14中定义了一个存放整型数的vector,里面存放了0~9。用pop_back函数,则把最晚进入vector的9删除。
4.?vector的增加
vector中的增加,可以有insert和push_back。insert是插入元素到某个位置中,push_back是在最后添加一个元素。
insert的函数原型有以下3种形式:
iterator insert(
iterator loc, const TYPE &val );
// 在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器
void insert(
iterator loc, size_type num, const TYPE &val );
// 在指定位置loc前插入num个值为val的元素
void insert(
iterator loc, input_iterator start, input_iterator end );
// 在指定位置loc前插入区间[start, end)的所有元素
【例3.15】 vector的查增删用法举例。
#include<algorithm>
#include<vector>
#include<iostream>
using namespace
std;
void print(
vector<int>v ){
vector<int>::iterator iter=v.begin();
for(;iter!=v.end();iter++)
cout<<*iter<<" ";
cout<<endl;
}
int main(){
vector<int> v; // 现在容器中有0个元素
int values[] = {1,3,5,7};
v.insert(v.end(), values+1, values+3); // 现在容器中有2个元素分别为:3,5
print(v);
v.push_back(9); // 现在容器中有3个元素分别为:3,5,9
print(v);
v.erase(v.begin()+1); // 现在容器中有2个元素分别为:3,9
print(v);
v.insert(v.begin()+1, 4); // 现在容器中有3个元素分别为:3,4,9
print(v);
v.insert(v.end()-1, 4, 6); // 现在容器中有7个元素分别为:3,4,6,6,6,6,9
print(v);
v.erase(v.begin()+1, v.begin()+3); // 现在容器中有5个元素分别为:3,6,6,6,9
print(v);
v.pop_back(); // 现在容器中有4个元素分别为:3,6,6,6
print(v);
v.clear(); //
现在容器中有0个元素
print(v);
if (true == v.empty()) // 如果容器为空则输出“null”
{
std::cout<<"null"<<std::endl;
}
return 0;
}
例3.15的程序的执行结果如图3-1所示。
例3.15中的语句:
v.insert(v.end(),
values+1, values+3);
就是将数组第2个元素和第3个元素的值插入到v.end()位置中,因为此时v还是空的,所以也就是往空vector里插入了两个元素。注意,这里只插入了两个元素,而没有插入3个元素。
v.erase(v.begin()+1);
v.begin()是指第1个元素,那v.begin()+1就是指第2个元素,即这里是删除第2个元素。
v.insert(v.end()-1,
4, 6);
v.end()是指最后一个元素的下一个位置,v.end()-1就是倒数第2个元素的前面一个位置,插入4个6,因此结果是3 4 6 6 6 6 9。
程序中v.clear()表示将v清空;v.empty()表示判断vector是否为空,如果为空,则返回true。