C++中STL vector总结

本文主要从vector的基础用法、vector作为函数返回值、vector作为函数参数三个方面进行介绍,有任何不当之处,欢迎指教。

一、vector基础用法

vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。,使用时需包含头文件:

#include <vector>

vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:

using std::vector;
vector<int> vInts;

或者连在一起,使用全名:

std::vector<int> vInts;

建议使用全局的命名域方式:

using namespace std;

在后面的操作中全局的命名域方式会造成一些问题。vector容器提供了很多接口,在下面的表中列出vector的成员函数和操作,c为vector对象。

函数表述
c.assign(b.begin(), b.begin()+3)b为向量,将b的0~2个元素构成的向量赋给c,即[beg; end)区间
c.assign(n,elem)将n个elem的拷贝赋值给c
c.at(idx)传回索引idx所指的数据,如果idx越界,抛出out_of_range
c.back()传回最后一个数据,不检查这个数据是否存在
c.front()返回c的第一个元素
c[i]返回c的第i个元素,当且仅当c[i]存在
c.clear()清空c中的元素
c.empty()判断c是否为空,空则返回ture,不空则返回false
c.pop_back()删除c向量的最后一个元素
c.erase(pos)删除pos位置的数据,传回下一个数据的位置
c.erase(beg,end)删除[beg,end)区间的数据,传回下一个数据的位置
c.push_back(5)在c的最后一个向量后插入一个元素,其值为5
c.insert(pos,elem)在pos位置插入一个elem拷贝,传回新数据位置
c.insert(pos,n,elem)在pos位置插入n个elem数据,无返回值
c.insert(pos,b.begin(),b.end())在pos位置插入在[beg,end)区间的数据,无返回值
c.size()返回c中元素的个数
c.capacity()返回c在内存中总共可以容纳的元素个数
c.resize(10)将c的现有元素个数调至10个,多则删,少则补,其值随机
c.resize(10,2)将c的现有元素个数调至10个,多则删,少则补,其值为2
c.reserve(100)将c的容量(capacity)扩充至100,也就是说现在测试c.capacity();的时候返回值是100.这种操作只有在需要给c添加大量数据的时候才显得有意义,因为这将避免内存多次容量扩充操作(当c的容量不足时电脑会自动扩容,当然这必然降低性能)
c.swap(b)b为向量,将c中的元素和b中的元素进行整体性交换
swap(c,b)同上
a==bb为向量,向量的比较操作还有!=,>=,<=,>,<

vector的初始化,可以有五种方式,举例如下:

(1)vector<Elem> c 创建一个空的vector

(2)vector <Elem> c(n) 创建一个vector,含有n个数据,数据均已缺省构造产生

(3)vector <Elem> c1(c2) 复制一个vector

(4)vector <Elem> c(n, elem) 创建一个含有n个elem值的vector

(5)vector <Elem> c(beg,end) 创建一个以[beg;end)区间的vector

(6)intb[7]={1,2,3,4,5,9,8};vector<int> a(b,b+7) 从数组中获得初值

vector的销毁,方法如下:

c.~ vector <Elem>() 销毁所有数据,释放内存

顺序访问vector的几种方式:

1、向向量a中添加元素

vector<int> a;
for(int i=0;i<10;i++)
a.push_back(i);

2、从数组中选择元素向向量中添加

int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=1;i<=4;i++)
b.push_back(a[i]);

3、从现有向量中选择元素向向量中添加

itn a[6] = {1,2,3,4,5,6};
vector<int> b;
vector<int> c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();it++)
    b.push_back(*it);

4、从文件中读取元素向向量中添加

ifstream in("data.txt");
vector<int> a;
for(int i; in>>i)
a.push_back(i);

5、易犯错误

vector<int> a;
for(int i=0;i<10;i++)
a[i]=i;
//这种做法以及类似的做法都是错误的。下标只能用于获取已存在的元素,而现在的a[i]还是空的对象

从向量中读取元素

1、通过at()函数读取,at()进行了边界检查,如果访问超过了vector的范围,将抛出一个异常

vector<int> 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();
}

2、通过遍历器方式读取

int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";

3、通过下标方式读取,operator[]不会进行边界检查

int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(int i=0;i<=b.size()-1;i++)
cout<<b[i]<<" ";

类和结构体存vector入实例:由于vector只允许一个占位,所以才将struct塞进vector,以弥补vector的不足

#include "stdafx.h"
#include <vector>
#include <string>
using namespace std;
class AClass
{
public:
    int num;
    string name;
};
struct AStruct 
{
    int num;
    string name;
};
void TestStruct()
{
 //类的使用
    AClass Ac;
    vector<AClass> vc;
    Ac.num=10;
    Ac.name="name";
    vc.push_back(Ac);
    AClass d;  
    for (vector<AClass>::iterator it=vc.begin();it<vc.end();++it)  
    {  
        d=*it;  
        cout<<d.num<<endl; 
    } 
 //结构体的使用
    AStruct As;
    vector<AStruct> vs;
    As.num=10;
    As.name="name";
    vs.push_back(As);
    AStruct ds;  
    for (vector<AStruct>::iterator it=vs.begin();it<vs.end();++it)  
    {  
        ds=*it;  
        cout<<ds.num<<endl; 
    } 
}
void TestPoint()
{
 //类的使用
    AClass *Ac=new AClass;
    vector<AClass *> vc;
    Ac->num=10;
    Ac->name="name";
    vc.push_back(Ac);
    AClass *d;  
    for (vector<AClass*>::iterator it=vc.begin();it<vc.end();++it)  
    {  
        d=*it;  
        cout<<d->num<<endl; 
    } 
}
int _tmain(int argc, _TCHAR* argv[])
{
    TestStruct();
    TestPoint();
    int n;
    cin>>n;
    return 0;
}

C++中将两个vector中的值整合到另一个vector中,vecB和vecA中有相同的struct个数,现在想将每个vecA中的每个a的值传给vecC中c1,每个vecB中的每个b的值传给vecC中c2,也就是将两个容器中的内容整合到新的容器C中

struct A
{
int a;
};
vector<A> vecA;
struct B
{
int b;
};
vector<B> vecB;
struct C
{
int c1;
int c2;
};
vector<C> vecC;

容器C和A、B中元素类型不同,迭代器类型就不同,所以不能用容器算法,使用迭代器遍历赋值,合并代码如下:

第一种方法:
for(vecA::const_iterator itA = vecA.begin(), VecB::const_iterator itB = vecB.begin();
        itA != vecA.end() && itB != vecB.end(); itA++, itB++){
        C c;
        c.c1 = (*itA).a;
        c.c2 = (*itB).b;
        vecC.push_back(c);
}
第二种方法:
void MergeVector(vector<A> &vectorA,vector<B> &vectorB,vector<C> &vectorC)
{
vector<A>::iterator pva;
vector<B>::iterator pvb;
vector<C>::iterator pvc;
pva = vectorA.begin();
pvb = vectorB.begin();
pvc = vectorC.begin();
while(pva!=vectorA.end())
{
*pvc->c1 = *pva->a;
*pvc->c2 = *pvb->b;
pva++;
pvb++;
pvc++;
}
}

建立两个int类型的向量vector,利用merge算法合并,再用sort算法对合并后算法排序

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> merge(vector<int> ,vector<int> );
int main()
{
vector<int> v1;
v1.push_back(4);
v1.push_back(6);
v1.push_back(2);
vector<int> v2;
v2.push_back(3);
v2.push_back(1);
v2.push_back(5);
vector<int> v3=merge(v1,v2);
sort(v3.begin(),v3.end());
for(vector<int>::iterator it=v3.begin();it!=v3.end();++it){
cout<<*it<<endl;
}
}
vector<int> merge(vector<int> v1,vector<int> v2)
{
v1.insert(v1.end(),v2.begin(),v2.end());
return v1;
}

压缩一个臃肿的vector

很多时候大量的删除数据,或者通过使用reserve(),结果vector的空间远远大于实际需要的。所有需要压缩vector到它实际的大小。resize()能够增加vector的大小。Clear()仅仅能够改变缓存的大小,所有的这些对于vector释放内存等九非常重要了。

我们可以通过一个vector创建另一个vector。让我们看看这将发生什么。假定我们已经有一个vector v,它的内存大小为1000,当我们调用size()的时候,它的大小仅为7。我们浪费了大量的内存。让我们在它的基础上创建一个vector。

std::vector<CString> vNew(v);
cout << vNew.capacity();

vNew.capacity()返回的是7。这说明新创建的只是根据实际大小来分配的空间。现在我们不想释放v,因为我们要在其它地方用到它,我们可以使用swap()将v和vNew互相交换一下?

vNew.swap(v);
cout << vNew.capacity();
cout << v.capacity();

有趣的是:vNew.capacity()是1000,而v.capacity()是7。

现在是达到我的目的了,但是并不是很好的解决方法,我们可以像下面这么写:

 std::vector<CString>(v).swap(v);

你可以看到我们做了什么?我们创建了一个临时变量代替那个命名的,然后使用swap(),这样我们就去掉了不必要的空间,得到实际大小的v。

二、vector作为函数返回值用法

在实际应用过程中,我们经常需要保存一系列的数据,有可能是一个值,点等,这时我们会用到vector。 有时候我们需要将vector作为一个函数的返回值,使用方法如下所示:

在被调用函数中声明一个vector变量,函数结束的时候返回vector变量。

vector<int> getSequence(int num){
    vector<int> sequence;
    for(int i=0;i<10;i++){
        sequence.push_back(i+num);
    }
    return sequence;
}
​
int main(){
    int num=9;
    vector<int> sequence;
    //在主调函数这边,只传入num 
    sequence=getSequence(num);
    //访问该vector的值的时候,也是直接访问即可
    for(vector<int>::iterator it=sequence.begin();it!=sequence.end();it++){
        cout<<*it<<endl;
    }
}

三、使用vector的引用在函数间传递

下面是一个例子,假设我要传入一个数,我的函数的功能是返回这个数后面十个数的序列:

我们将函数返回值设定为bool类型,vector作为函数的参数,添加引用,保存数据

#include<iostream>
#include<vector>
using namespace std;
​
/*
输入一个数,返回这个数后面的十个数字序列
注意参数的这个 & 符号不能省略
*/ 
bool getSequence(int num,vector<int>& sequence){
    for(int i=0;i<10;i++){
        sequence.push_back(i+num);
    }
    return true;
}
​
int main(){
    int num=9;
    vector<int> sequence;
    //在主调函数这边,直接传入该vector变量
    getSequence(num,sequence);
    //访问该vector的值的时候,也是直接访问即可
    for(vector<int>::iterator it=sequence.begin();it!=sequence.end();it++){
        cout<<*it<<endl;
    }
}

四、几种重要的算法,使用时需要包含头文件: #include <algorithm>

(1)sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列

(2)reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1

(3)copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素

(4)find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值