C++STL(二)——vector容器
STL——vector容器
- vector对象的概念
- vector基本操作
- vector对象的初始化、赋值
- vector查找、替换(已在上一片 string类 博客总结过了,不再总结)
- vector添加、弹出元素(头部、尾部)
- vector容器的遍历(通过数组的方式、通过迭代器)
- vector删除、插入操作(指定元素删除/插入、区间删除/插入、一次插入多个相同的元素)
- 迭代器介绍(输入迭代器、输出迭代器、正向迭代器、双向迭代器)
- vector举例应用
在这片文章中我参考了许多人的博客,甚至有一些部分是直接copy的,最终做了一个详细的vector用法总结
vector用法参考
vectot容器的简介
- vector 是一个将元素置于动态数组中加以管理的容器。
- vector 支持随机存取元素(支持索引值直接存取,用[]操作符或 at()方法,来下标来访问)
- vecotr 在尾部添加和移除元素非常快,但是在中间和头部添加和移除却很费事。
- vector存储数据时,会分配一个存储空间,如果继续存储,该分配的空间已满,就会分配一块更大的内存,把原来的数据复制过来,继续存储,这些性能也会一定程度上会有损耗
vector基本操作
(1). 容量
向量大小: vec.size();
向量最大容量: vec.max_size();
更改向量大小: vec.resize();
向量真实大小: vec.capacity();
向量判空: vec.empty();
减少向量大小到满足元素所占存储空间的大小: vec.shrink_to_fit(); //shrink_to_fit
(2). 修改
多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值
末尾添加元素: vec.push_back();
末尾删除元素: vec.pop_back();
任意位置插入元素: vec.insert();
任意位置删除元素: vec.erase();
交换两个向量的元素: vec.swap();
清空向量元素: vec.clear();
vector类的对象的构造
//vector 采用模版类来实现 vector<T> vec;
vector<int> v1 //从模版实例化出存放int类型元素的 v1 容器
vector<double> v2 //从模版实例化出存放double类型元素的 v1 容器
//vector 尖括号内可以实例化出 指针类(包括自定义的数据类型的指针)型和自定义的 数据类型的 容器
vector<int *> v3// 定义存放 int型变量的地址的容器
class A {}; // 自几定义数据类型 A
vector<A> v4; //定义存放A类型数据的容器
vector<A *> v5;//定义存放 A类型变量的地址的容器
//⚠️注意:由于容器元素的初始化/赋值是按值传递复制的进行的,所以此时 A类 必须提供拷贝构造函数,以保证 A类的对象之间拷贝正常
初始化
v1.push_back(1); //向v1中添加一个 1
v1.push_back(2); //向v2中添加一个 2
v1.push_back(3); //向v3中添加一个 3
int ar[3] = {1,3,5};
vector<int> vec={1,3,5}; //用列表初始化
vector<int>v2 = v1; //用vector的拷贝构造函数
vector<int>v3(v1);
vector<int>v4(v1.begin(),v1.end());//区间初始化
vector<int>v5(ar,ar+3); //用数组区间初始化
vector<int>v6(5,0); //用五个0进行初始化
赋值
//vector赋值
//第一类赋值法
v4.assign(10,0); //给v4赋上10个零
v3.assign(ar,ar+2);
v2.assign(v1.begin(),v1.end());
//第二类赋值法(⚠️运用下标法 [] 必须先给vector容器申请空间,以供下标访问否则出错,如果此时用push_back()将把元素插入到先前申请的空间之后)
vector<int> v5(10); //提前申请存储10元素的空间,此时10个元素的值均为0
for(int i=0;i<10;i++)
v5[i]=i+1;
//第三类赋值法,通过迭代器的方式去赋值
for(vector<int>::iterator it =v5.begin();it<v5.end();it++)
*it = 0;
添加、弹出元素(头部、尾部)
vector<int> v1;
//vector 的增添、弹出、删除元素
//添加
v1.push_back(1); //向v1中添加一个 1
v1.push_back(2); //向v2中添加一个 2
v1.push_back(3); //向v3中添加一个 3
print(v1);
//弹出
v1.pop_back(); //弹出尾部的一个元素
print(v1);
//尾元素的访问与修改
cout<<v1.back(); //通过back()函数去访问v1的尾元素
cout<<v1.front();//通过front()函数去访问v1的首元素
v1.back() = 10; //由于back()函数返回值为引用,所以可以通过back(),来改变尾元素的值
v1.front() = 20; // 与⬆️同理
遍历
vector<int> v1={1,3,5};
//vector的遍历
//1.用for循环
for(int i=0;i<3;i++)
cout<<v1[i];
//2.用基于范围的for循环
for(int &i:v1)
{
cout<<i;
i = 10; //有 i 被声明的时候是以引用的方式,所以可以通过 i 来改变v1中元素的值
}
//3.用迭代器
for(vector<int>::iterator it = v1.begin();it<v1.end();it++)
{
cout<<*it;
* it = 10; //通过it指针去改变v1的值
}
删除,插入操作
int ar[3] = { 1, 3, 5};
vector<int> v1={1,2,3};
vector<int> vec={1,3,5};
//删除操作
注意⚠️:用erase()删除完后元素后,它的返回值是一个指向下一个元素(挨着最后一个被删除的元素的元素)的迭代器
vec.erase(vec.begin(),vec.end()); //删除[vec.begin(),vec.end())区间的元素
vec.erase(vec.begin()); //删除vec.begin()这个位置的元素
//插入
vec.insert(vec.begin(), 0); //在vec.begin() 位置之前 插入元素
vec.insert(vec.end(), v1.begin(),v1.end()); //在vec.end() 之前插入在[v1.begin(),v1.end())区间内的元素
vec.insert(vec.begin(),10,0); //在vec.begin()之前插入10个0元素
vec.insert(vec.begin(),ar,ar+3);![ebd4c8678baf58da184575ee8ca5b528.png](evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p334)
迭代器
迭代器的介绍:
- 迭代器类似于指针类型,它只想一个特定的位置,它也提供了对对象的间接访问
- 指针是C语言中就有的东西,而迭代器是C++中才有的
- 使用迭代器:和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员,比如,容器都有的成员begin和end,其中begin成员负责返回指向容器第一个元素的迭代器,如:auto b = v.begin();end成员则负责返回指向容器的尾元素的下一个位置的迭代器,也就是说指向的是容器的一个本不存在的尾部。如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。
- 迭代器提供一个对容器对象或者string对象访问的方法,并且定义了容器范围
输入、输出迭代器
- 输入迭代器:又叫“只读迭代器“,它只能从容器中读取元素,一次读出一个迭代器向前移,同一个输入迭代器不能遍历两次容器
- 输出迭代器:又叫“只写迭代器”,它只能从容器总写入元素,一次写入一个迭代器向前移,同一个输出迭代器不能遍历两次容器
正向迭代器、双向迭代器
- 正向迭代器:所谓正向迭代器指的是只能正向走,而不能反向走,一个在一个指着(停留在)一个元素多次,而且一次移动多个位置,可以通过 ++ += (不可以通过 – -= 运算符)
- 双向迭代器:所谓正向迭代器指的是可以可以正反两个方向走,支持随机访问容器,一次移动多个位置,可以通过 ++ – += -= 运算符来完成
迭代器理解
- 迭代器的类型:
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xP89GMwr-1574571844427)(evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p332)]
- 1vector::iterator it;//it可以读写vector的元素
- 2string::iterator it2;//it2可以读写string对象中的字符
- 3vector::const_iterator it3;//it3只能读元素,不能写元素
- 4string::const_iterator it4;//it4只能读字符,不能写字符
- 迭代器的区别
const_iterator和常量指针差不多,能读取但不能修改它所指的元素值,而iterator可读可写。如果容器或string对象是一个常量,只能使用const_iterator,如果不是常量,那么既能使用iterator又能使用const_iterator。
如果容器或对象只需读操作而无需写操作的话最好使用常量类型(const_iterator),为了便于获取常量迭代器,C++11新引入了两个新函数,分别是cbegin和cend,类似于begin和end,不同之乎在于只能返回const_iterator.
注意:但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
- 迭代器运算:
1iter + n 迭代器加上一个数值仍得一个迭代器,所指位置向前移动n个元素
2iter - n 迭代器减去一个数值仍得一个迭代器,所指位置向后移动n个元素
3iter += n 等价于iter + n
4iter -= n 等价于iter - n
5iter1 - iter2 两个迭代器相减的结果是他们之间距离,其类型是名为difference_type的带符号整数
6 >、>=、<、<= 位置离begin近的元素较小
迭代器的应用
//迭代器的应用
//1. 迭代器的声明
vector<int> v1{1,3,5};
vector<int>::iterator it1 = v1.begin(); //声明一个双向迭代器,(begin())并赋值为v1元素的首地址
vector<int>::const_iterator it2 = v1.cbegin(); //只能读容器的值,而不能改变容器的值,cbegin(),是一个指向容器首元素的地址常量,cend()同理如此
vector<int>::reverse_iterator it3 = v1.rbegin(); //声明一个反向迭代器,(rbegin()指向最后一个元素,rend()指向容器第一个元素位置之前)
for( ;it2 < v1.cend();it2++)
{
cout<<*it2;
//*it2 = 10; 这一条错误 因为 it2 是常量迭代器
}
for( ;it3 < v1.rend();it3++)
{
cout<<*it3<<endl; //输出结果:3 2 1
*it3 = 10; //通过指针去赋值
cout<<*it3<<endl;
}
- 对rbegin()和rend()的理解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h1dfhtf2-1574571844431)(evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p334)]
vector与迭代器 举例应用
//关于STL中vector容器的学习,编译运行后边看代码,边看执行结果效果更佳,不过看别人的代码一百遍,不如自己动手写一遍
#include <vector>//头文件
#include <iostream>
#include <algorithm>
using namespace std;
void print(vector <int> v);
bool mycmpare(const int &a, const int &b){
return a>b;
}
int main ()
{
//创建vector对象三种常用的方式,此处存储元素类型是int,还可以是double、char、long long等基本数据类型,甚至是string基本字符序列容器
vector <int> v1;//不指定容器的元素个数的定义一个用来存储整型的向量容器
cout<<"v1:"<<endl;
print(v1);
/*运行结果
v1:
大小为:0
*/
vector <int> v2(5);//指定容器的元素个数的定义一个大小为10的用来存储整型的向量容器,默认初始化为0
cout<<"v2:"<<endl;
print(v2);
/*运行结果
v2:
大小为:5
0 0 0 0 0
*/
vector <int> v3(5,1);//也可指定初始值,此处指定为1
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:5
1 1 1 1 1
*/
//另外事先指定不指定大小都无所谓,指定了大小也可以随时使用push_back()对vector容器进行尾部扩张
v1.push_back(1);//向空的vector容器尾部扩张,追加元素为1
cout<<"v1:"<<endl;
print(v1);
v3.push_back(2);//向已有元素的vector容器尾部扩张,追加元素为2
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v1:
大小为:1
1
v3:
大小为:6
1 1 1 1 1 2
*/
//插入元素使用insert()方法,要求插入的位置是迭代器的位置,而不是元素的下标
v3.insert(v3.begin(),3);//在最前面插入3
cout<<"v3:"<<endl;
print(v3);
v3.insert(v3.end(),3);//在末尾追加3,此处等同于push_back()
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:7
3 1 1 1 1 1 2
v3:
大小为:8
3 1 1 1 1 1 2 3
*/
int i;
for(i=0;i < v3.size();i++){//只可赋值到已扩张位置
v3[i]=i;
}
//要删除一个元素或者一个区间中的所有元素时使用erase()方法
v3.erase(v3.begin()+2);//删除第2个元素,从0开始计数
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:7
0 1 3 4 5 6 7
*/
v3.erase(v3.begin()+1,v3.begin()+3);//删除第1个到第3个元素区间的所有元素
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:5
0 4 5 6 7
*/
//由结果可知,erase()方法同insert()方法一样,操作的位置都只是迭代器的位置,而不是元素的下标
//要想清空vector(),使用clear()方法一次性删除vector中的所有元素
cout<<"v2:"<<endl;
print(v2);
/*运行结果
v2:
大小为:5
0 0 0 0 0
*/
v2.clear();
if(v2.empty()) cout<<"v2经过使用clear()方法后为空\n";
print(v2);
/*运行结果
v2经过使用clear()方法后为空
大小为:0
*/
//要想将向量中某段迭代器区间元素反向排列,则使用reverse()反向排列算法,需要添加algorithm头文件
cout<<"v3反向排列前:"<<endl;
print(v3);
reverse(v3.begin(),v3.end());//全部反向排列
cout<<"v3反向排列后:"<<endl;
print(v3);
/*运行结果
v3反向排列前:
大小为:5
0 4 5 6 7
v3反向排列后:
大小为:5
7 6 5 4 0
*/
//要想将向量中某段迭代器区间元素进行排序,则使用sort()算法
cout<<"v3升序排列前:"<<endl;
print(v3);
sort(v3.begin(),v3.end());//默认升序排列
cout<<"v3升序排列后:"<<endl;
print(v3);
/*运行结果
v3升序排列前:
大小为:5
7 6 5 4 0
v3升序排列后:
大小为:5
0 4 5 6 7
*/
//自定义排序比较函数,此处降序
cout<<"v3降序排列前:"<<endl;
print(v3);
sort(v3.begin(),v3.end(),mycmpare);
cout<<"v3降序排列后:"<<endl;
print(v3);
/*运行结果
v3降序排列前:
大小为:5
0 4 5 6 7
v3降序排列后:
大小为:5
7 6 5 4 0
*/
}
void print(vector <int> v)
{
//cout<<"下标方式访问:"<<endl;
cout<<"大小为:"<<v.size()<<endl;
int i;
for(i=0;i< v.size();i++){
cout<<v[i]<<' ';
}
cout<<endl<<endl;
/*cout<<"用迭代器访问:"<<endl;
//定义迭代器变量it,类型与容器元素类型保持一致
vector<int>::iterator it;
for(it=v.begin(); it != v.end(); it++){
cout<<*it<<' ';
}
cout<<endl<<endl;*/
}
C++STL(二)——vector容器的更多相关文章
- 带你深入理解STL之Vector容器
C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...
- 跟我一起学STL(2)——vector容器详解
一.引言 在上一个专题中,我们介绍了STL中的六大组件,其中容器组件是大多数人经常使用的,因为STL容器是把运用最广的数据结构实现出来,所以我们写应用程序时运用的比较多.然而容器又可以序列式容器和关联 ...
- 【C++】STL,vector容器操作
C++内置的数组支持容器的机制,但是它不支持容器抽象的语义.要解决此问题我们自己实现这样的类.在标准C++中,用容器向量(vector)实现.容器向量也是一个类模板.标准库vector类型使用需要的头 ...
- STL中vector容器实现反转(reverse)
vector容器中实现可以通过以下两种方式实现: #include "stdafx.h" #include <vector> #include <iostream ...
- STL 查找vector容器中的指定对象:find()与find_if()算法
1 从vector容器中查找指定对象:find()算法 STL的通用算法find()和find_if()可以查找指定对象,参数1,即首iterator指着开始的位置,参数2,即次iterator指着停 ...
- STL:vector容器用法详解
vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组.像数组一样,vector类也用从0开始的下标表示元素的位置:但和数组不同的是,当vector对象创建后,数组的元素个数会随着ve ...
- STL之vector容器详解
vector 容器 vector是C++标准模版库(STL,Standard Template Library)中的部分内容.之所以认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单的说: ...
- (转载)C++STL中vector容器的用法
vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说vec ...
- STL笔记(に)--vector容器
Vector 1.可变长的动态数组 2.需包含头文件#include<vector> (当然,如果用了万能头文件#include<bits/stdc++.h>则可忽略) 3.支 ...
- [转]STL之vector容器详解
vector 容器 vector是C++标准模版库(STL,Standard Template Library)中的部分内容.之所以认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单的说: ...
随机推荐
- 关于使用Binlog和canal来对MySQL的数据写入进行监控
先说下Binlog和canal是什么吧. 1.Binlog是mysql数据库的操作日志,当有发生增删改查操作时,就会在data目录下生成一个log文件,形如mysql-bin.000001,mysql ...
- CVPR 2020 三篇有趣的论文解读
作者 | 文永亮 学校 | 哈尔滨工业大学(深圳) 研究方向 | 视频预测.时空序列预测 目录 AdderNet - 其实不需要这么多乘法 Deep Snake for Real-Time Insta ...
- 【Java实用工具】——使用oshi获取主机信息
最近在筹划做一个监控系统.其中就要获取主机信息,其中遇到一些问题.在此做个记录,以便以后查阅. 在该监控系统中,想要做到主机的CPU.内存.磁盘.网络.线程.JVM内存.JVM GC 等维度的监控,J ...
- 如何使用Kibana
目录 前言 一.安装 二.加载自定义索引 三.如何搜索数据 四.如何切换中文 五.如何使用控制台 六.可视化图表 七.使用仪表盘 前言 Kibana 是为 Elasticsearch设计的开源分析和可 ...
- 在Windows中像Linux里一样使用CMake和make
1. 安装GCC环境 1.1 安装MinGW(Minimalist GNU for Windows) 首先下载MinGW,并安装.安装完成之后运行MinGW Installer.界面如下.勾选自己需要 ...
- IntelliJ IDEA 常用快捷键(转载)
转自:http://www.open-open.com/lib/view/open1396578860887.html Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 ...
- How to do error checking in CUDA(如何在CUDA里做错误检查)
https://codeyarns.com/2011/03/02/how-to-do-error-checking-in-cuda/ Error checks in CUDA code can hel ...
- CSS每日学习笔记(0)
7.29.2019 1. CSS 指层叠样式表 (Cascading Style Sheets) 样式定义如何显示 HTML 元素 样式通常存储在样式表中 把样式添加到 HTML 4.0 中,是为了解 ...
- Docker学习-私有仓库docker-registry的使用
1.从docker官方仓库下载registry 2.将registry放进容器内 3.在官方下载镜像上传本地仓库 4.私有仓库docker-registry使用的常见问题 5.配置阿里云镜像加速器 假 ...
- HBU-数据库第五周作业
第五周数据库作业 注意 MySQL的数据库名.表名.列名.别名大小写规则是这样的: 1.数据库名与表名是严格区分大小写的: 2.表的别名是严格区分大小写的: 3.列名与列的别名在所有的情况下均是忽略大 ...