C++之STL(vector)(蓝桥杯备战)

vector(向量)

  • vector实际上就是对动态数组的封装
  • 可以先数组一样可以使用下标访问元素,若vector长度为n,则其下标为0~n-1
  • 根据下标访问元素效率更高
  • vector对象的空间随着插入删除操作自动调整
  • 因为空间自动调整比较耗时,因此频繁的插入删除回事vector的效率下降

一.vector上的基本操作

1.vector对象创建

创建一个空向量

vector<int> v1;     //int类型向量

vector<string> s1; //string类型向量

从已有向量复制创建向量

vector<int> v2(v1);    //拷贝v1内容到v2(类比于拷贝构造函数)

创建10个元素的向量

vector<string> s2(10);

创建10个元素的向量,所有元素都为1.5

vector<double> v3(10,1.5);

创建向量指针

vector<int> *prec = new vector<int>(10,-5);

2.vector尾部添加元素

使用push_back()函数向vector尾部添加元素

#include<iostream>
#include<vector>                 //使用vector必备

using namepace std;

int main()
{
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    return 0;              
}

3.vector任意位置插入元素

使用insert()函数向vector添加元素

#include<iostream>
#include<vector>                 //使用vector必备

using namepace std;

int main()
{
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.insert(v1.begin(),0);        //头部插入
    v1.insert(v1.end(),4);          //尾部插入
    v1.insert(v1.end()-1,3);        //倒数第二位置插入
    return 0;               //v1.begin(),v1.end()获取相应位置的迭代器
}

4.vector用下标访问元素

#include<iostream>
#include<vector>                 //使用vector必备

using namepace std;

int main()
{
    vector<int> v1;
    ……    ……
    v1.insert(v1.end()-1,3);        //倒数第二位置插入
    v1[4]=10;    //v1[5]=6;越界错误
    for(int i=0;i<v1.size();i++)    //v1.size(),vector的长度
        cout<<v1[i]<<" ";
    return 0;               
}

5.vector删除尾部元素

使用pop_back()删除

#include<iostream>
#include<vector>                 //使用vector必备

using namepace std;

int main()
{
    vector<int> v1;
    ……    ……
    v1[4]=10;    //v1[5]=6;越界错误
    v1.pop_back();  //删除10
    return 0;               
}

6.vector删除任意元素

使用erase()删除任意位置元素

#include<iostream>
#include<vector>                 //使用vector必备

using namepace std;

int main()
{
    vector<int> v1;
    ……    ……
    v1[4]=10;    //v1[5]=6;越界错误
    v1.pop_back();  //删除10
    v1.erase(v1.begin());  //删除0
    v1.erase(v1.begin(),vi.end());    //全删,也可以使用v1.clear(),全删
    return 0;               
}

7.向量大小相关函数

v.size() 返回向量的大小
v.max_size() 返回向量可容纳的最大个数
v.empty() 返回向量时候为空
v.resize(n) 调整向量大小,使其可以容纳n个元素,如果n<v.size(),则删除多出来的元素;否则,添加新元素
v.iesize(n,t) 调整向量的大小,使其可以容纳n个元素,所有新添加的元素初始化为t
v.capacity() 获取向量的容量,在分配内存空间之前所能容纳的元素个数

二.vector上的迭代器

1.迭代器的基本信息

向量上的迭代器定义、使用

vector<int>::iterator it;
 *it = 5; 

vector上迭代器支持随机访问:

  • 提供读写操作
  • 并能在数据中随机移动(前后,跳跃式)

用加、减操作移动迭代器:

it++; ++it; //指向下一元素
it--; --it; //指向前一元素
it + i;     //返回指向 it 后面的第i个元素的迭代器
it – i;    //返回指向 it 前面的第i个元素的迭代器

用 <, <=, >, >=,==,!= 判断迭代器前后、相等关系:
it1 < it2 // 表示 it1 在 it2 之前

该特性在一部分情况下成立!

2.begin()和end()函数

每种容器都定义了一对命名为begin和end的函数,用于返回 迭代器。如果容器中有元素,由begin返回的迭代器指向第一 个元素

it = v1.begin(); // 指向v1[0]

由 end 返回的迭代器指向vector的末端元素的下一个。通常 称为超出末端迭代器,表明它指向了一个不存在的元素

it = v1.end(); // 指向末端元素的下一个

如果vector为空,begin返回的迭代器不end返回的迭代器相同

看到这里,我们可以发现,其实在所谓的迭代器中,这些许多操作和我们在学习栈、队列等基本数据结构时是类似的,我们可以将两者对比着来学习、理解。

3. 用迭代器读取元素

#include<iostream>
#include<vector>

using namespace std;

int main()
{
    vector<int> v1;
    for(int i=1; i<10; i++)
        v1.push_back(i); // 添加1~9
    vector<int>::iterator it;
    for(it=v1.begin(); it<v1.end(); it++)
        if(*it%2==0) cout<<*it<<" ";
    return 0;
}

4. 以迭代器为参数的插入删除函数

v.insert(p,t) 在迭代器p所指向的元素前面插入值为 t 的元素
v.insert(p,n,t) 在迭代器p所指向的元素前面插入n个值为t的新元素
v.insert(p,b,e) 在迭代器p所指向的元素前面插入迭代器b和e标记的范围内的元素
v.erase(p) 删除迭代器p指向的容器中的元素
v.erase(b,e) 删除迭代器b和e所标记范围内的元素

通过迭代器进行删除和插入

vector<int> v2(3, 1);
vector<int> v1(4, 0);
v1.insert(v1.begin(), 5);     // 在头部插入5
v1.insert(v1.end(), 7 );      // 在尾部插入7

vector<int>::iterator it = v1.begin() + 4;    // 在下标为4处插入9
v1.insert(it, 9 );
for(it=v1.begin(); it<v1.end(); )     // 删除偶数元素
{
if(*it%2==0) it=v1.erase(it);
else it++;
}
v2.insert(v2.begin(),v1.begin(),v1.begin()+2);    //将v1的一部分拷贝到v2

如果我们仔细观察上面的代码,我们可以发现一个细节:

it=v1.erase(it);

在我们以往的编程过程中,it是会在for循环中自动增加,这是为什么?

如果我们运行以下代码,我们会发现运行出错

vecotr<int>::iterator it = vc.begin();
for( ; it != vc.end(); it++ )
{ if( ***** ) vc.erase(it); }

这主要是因为在vector中,erase()在删除元素后,迭代器it失效,并没有指向下一个元素,而解决的方法如下:

for(it=v1.begin(); it<v1.end(); ) 
{
if(*******) it=v1.erase(it);
else it++;
}

我们可以这样做的原因主要是因为在C++11标准中,erase() 会返回一个iterator,这个iterator 指向了“当前删除元素的后继元素” 。我们把这个值赋给it,实现了让it指向下一个元素的操作。

三.vector上的应用算法

常用算法包括:排序sort()、查找find()、替换replace()、合并merge()、反序reverse()、统计count()等。

PS:许多算法都是以迭代器为参数。 有的算法返回一个迭代器。

算法主要在头文件<algorithm>和<numetic>中定义

1.find()

形式:find(first,last,val)

first 和 last 这两个参数都是容器的迭代器,它们 给出了容器中的查找区间起点和终点。

这个区间是个左闭右开的区间[first,last),即区间的起 点是位于查找范围之中的,而终点不是

val参数是要查找的元素的值

函数返回值是一个迭代器。如果找到,则该迭代 器指向被找到的元素。如果找不到,则该迭代器指向查找区间终点。

2.sort()

形式:sort(first,last);

first 和 last 这两个参数都 是容器的迭代器,它们给 出了容器中的查找区间起 点和终点

3.merge()

形式:merge(f1,e1,f2,e2,p);

f1、e1、f2、e2、p都是迭代器

有序序列v1中[f1, e1)和有序序列v2中[f2, e2)合并成有序序列,存入p的前面

4.其他算法示例

replace( first, last, old, new )

作用:将 [ first,last ) 范围内的所有值为old的替换为new

reverse(start, end)

作用:将序列中 [start, end) 范围反转排列顺序

count(start, end, searchValue)

作用:统计[start, end) 范围内等于searchValue的元素个数

accumulate(first, last, init)

作用:将[ first,last )范围内的所有值相加,再加上init后返回

发布了13 篇原创文章 · 获赞 6 · 访问量 1815
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览