vector常见接口的使用(基于c++标准库中的STL)

news2025/1/13 15:32:51

前言 

        vector是STL中的重要容器,在平时使用中较常见。学会使用它以及了解它的核心原理对于我们学习它是很有帮助的。vector是可以动态增长的数组。vector可以像数组一样进行随机访问,这是vector最大的优势之一,因为支持随机访问就间接的支持了排序,二分查找等。这样可以更好的管理数据。vector也有一些缺陷除了尾插尾删之外,其他位置的插入和删除都需要挪动数据,因此会消耗线性的时间复杂度,所以效率较低,vector插入数据当内存不足的时候需要扩容,扩容也是有代价的。 

目录

1.构造函数

2.迭代器

3.容量空间 

        3.1容量空间 

        3.2空间增长问题 

4.增删查改

5.迭代器失效

        5.1迭代器失效

        5.2解决方法


1.构造函数

 

例如:

void testVector()
{
	vector<int> v1;//无参的构造函数
	vector<int> v2(5, 2);//构造有5个2的list
	vector<int> v3(v2);//拷贝构造
}

2.迭代器

iterator
iterator的使用接口说明
begin+endbegin()是获取第一个元素的迭代器,end()是获取最后一个元素的下一个位置的迭代器
rbegin+rendrbegin()是获取最后一个元素的迭代器,end()是获取第一个元素的上一个位置的迭代器

 例如:

void print(const vector<int>& v1)
{
	vector<int>::const_iterator cit = v1.cbegin();//const修饰的迭代器
	while (cit != v1.cend())
	{
		cout << *cit << " ";
		cit++;
	}
	cout << endl;
}
void testVector2()
{
	vector<int> v1;//无参的构造函数
	//尾插
	v1.push_back(0);
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	v1.push_back(7);
	//正向迭代器遍历
	vector<int>::iterator it = v1.begin();
	while (it != v1.end())
	{
		cout << *it << " " ;
		it++;
	}
	cout << endl;
	//逆向迭代器
	vector<int>::reverse_iterator rit = v1.rbegin();
	while (rit != v1.rend())
	{
		cout << *rit << " " ;
		rit++;
	}
	cout << endl;
	print(v1);
}

3.容量空间 

        3.1容量空间 

容量空间
容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断vector是否为空
resize改变vector的size
reserve改变vector的capacity

 例如:

void testVector5()
{
	vector<int>v1;
	v1.push_back(0);
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	cout << v1.size() << endl;//打印v1的size
	cout << v1.capacity() << endl;//打印v1的capacity
	cout << v1.empty() << endl;//判断v1是否为空
	v1.resize(5);//改变vector的size
	for (auto e : v1)
		cout << e<<" ";
	cout << endl;
	v1.resize(10,6);
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
	v1.reserve(20);//改变vector的容量
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
	cout << v1.capacity() << endl;
}

        3.2空间增长问题 

        我们一起来看看下面的代码:

int main()
{
	//测试vector的扩容机制
	vector<int> v1;
	size_t sz = v1.capacity();
	cout << "是否扩容" << endl;
	for (int i = 0; i < 1000; i++)
	{
		v1.push_back(i);
		if (sz != v1.capacity())
		{
			
			cout << "capacity changed:  " ;
			cout << sz << endl;
			sz = v1.capacity();
		}
	}

	return 0;
}

         在vs下的结果:

是否扩容
capacity changed:  0
capacity changed:  1
capacity changed:  2
capacity changed:  3
capacity changed:  4
capacity changed:  6
capacity changed:  9
capacity changed:  13
capacity changed:  19
capacity changed:  28
capacity changed:  42
capacity changed:  63
capacity changed:  94
capacity changed:  141
capacity changed:  211
capacity changed:  316
capacity changed:  474
capacity changed:  711 

        在g++下的运行结果:

capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128

capacity changed: 256
capacity changed: 512
capacity changed: 1024

       我们发现在不同的编译器下面vector的增长速度是不同的,vs下面是1.5倍,g++下面是2倍。

vs是PJ版本的STL,g++是SGI版本的STL。 vector的扩容速度不是固定的,要根据具体需求来定 ,扩容也不是越快越好,每次扩容的倍数越多,可能被浪费的空间也就越多,但是如果扩容的倍数较小的话,插入数据频繁时要多次扩容。扩容时开辟新空间,拷贝数据,释放旧空间都是有代价的。

         reserve可以改变容量如果我们预先知道要插入多少数据,直接开好空间,就不需要扩容了。如下:

int main()
{

	vector<int> v1;
	v1.reserve(1000);//先开辟好要插入数据的空间
	size_t sz = v1.capacity();
	cout << sz;
	for (int i = 0; i < 1000; i++)
	{
		v1.push_back(i);
		if (sz != v1.capacity())//判断容量是否增加
		{
			
			cout << "capacity changed:  " 
			cout << sz << endl;
			sz = v1.capacity();//将新的capacity赋给sz
		}
	}
	return 0;
}

4.增删查改

增删查改
vector增删查改接口说明
push_back尾插
pop_back尾删
find查找(这个是算法模块的实现,不是vector的成员接口)
insert任意位置的插入(在position之前插入val )
erase删除position位置
swap交换两个vector的数据空间
operator[]像数组一样访问

        例如: 

void testVector3()
{
	vector<int>v1;
	//尾插尾删
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	v1.push_back(7);

	v1.pop_back();
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
	v1.insert(v1.begin(), 5, 7);//头插5个7
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
	v1.insert(v1.begin() + 5, 9);//position位置插入9
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
	//删除position位置的元素
	v1.erase(v1.begin());
	v1.erase(v1.begin()+1);
	v1.erase(v1.begin())+3;
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
	vector<int>::iterator it = find(v1.begin(), v1.end(), 9);//查找val值,返回的是val值所对应的迭代器
	if (it != v1.end())//确保迭代器有效
	{
		*it = 20;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
}

 

void testVector4()
{
	vector<int> v1(5,2);
	vector<int> v2(2,5);
	for (auto e : v1)//打印v1
		cout << e;
	cout << endl;
	for (auto e : v2)//打印v2
		cout << e;
	cout << endl;
	swap(v1, v2);//交换v1和v2
	for (auto e : v1)//打印v1
		cout << e;
	cout << endl;
	for (auto e : v2)//打印v2
		cout << e;
	cout << endl;
}

5.迭代器失效

        5.1迭代器失效

        你是否遇到过这样的代码:

int main()
{
	vector<int>v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	v1.push_back(7);
	vector<int>::iterator it = v1.begin();
	v1.push_back(8);
	v1.push_back(9);
	v1.push_back(10);
	v1.push_back(11);
	
	while (it != v1.end())
	{
		cout << *it << " ";
		it++;
	}

	return 0;
}

        运行上面的这段代码程序就会奔溃。为什么呢?

        这就要涉及到迭代器失效的问题了。因为取出迭代器之后还对vector进行的尾插操作,尾插使得vector增容(增容会开辟新空间,拷贝数据释放旧空间)。此时的迭代器指向的还是旧的空间,此时对迭代器进行操作经已是不合法的了。 

         请接着往下看:

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(8);
	v1.push_back(6);

	//删除v1中的偶数
	vector<int> ::iterator it = v1.begin();
	while (it !=v1.end())
	{
		if (*it % 2 == 0)
		{
			v1.erase(it);
		}
		else 
		{
			++it;
		}
	}
	for (auto e : v1)
		cout << e << " ";
	return 0;
}

        上面的这段代码在vs下运行程序会奔溃,因为删除it以后,it就失效了,这里是指it的位置失效了,再解引用或者++就不行了,vs的编译器对此进行了严格的检查所有会报错,但是在g++没有进行严格的语法检查,可以运行这个程序。

        总结,不管在哪个平台下,erase(it)以后it就失效了,只是导致的结果不一样而已。

        改进,erase(it)以后 接收erase的返回值,因为erase返回的是紧挨着it位置的下一个位置的迭代器。

        如下:

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(8);
	v1.push_back(6);

	//删除v1中的偶数
	vector<int> ::iterator it = v1.begin();
	while (it !=v1.end())
	{
		if (*it % 2 == 0)//迭代器失效,it的位置不对了,++就不行,编译器检查的结果,g++下不一定会报错,导致结果不对
		{
			v1.erase(it);
		}
		else 
		{
			++it;
		}
	}
	for (auto e : v1)
		cout << e << " ";
	return 0;
}

 

        5.2解决方法

       凡是涉及erase,insert,pop_back,push_bakc等有关内存的操作都可能导致迭代器失效。对于上述第一种问题,只有在将要使用迭代器的时候再去求迭代器。在使用迭代器之前要对迭代器进行赋值。就可以解决了。  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/589918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TRUNCATE TABLE t 和DELETE FROM t的区别

背景 最近再工作中,遇到一个问题,就是再代码执行过程中,出现异常时并不会去回滚代码.导致数据不一致,最初以为是Transactional这个注解没有生效 Spring中什么时候Transactional会失效 因为Spring事务是基于代理来实现的,所以某个加了Transactional的方法只有是被代理对象调用…

APP测试面试题快问快答(二)

1.请问App测试的主要内容包含&#xff1f; 功能测试&#xff1a; 业务逻辑正确性测试&#xff1a;依据产品文档->测试用例编写。 界面的测试 界面测试&#xff1a;依据产品UI设计文档&#xff08;高保真图&#xff0c;原型图&#xff09;。 升级&#xff0c;安装&#…

研发工程师玩转Kubernetes——定时任务

定时任务是指可以制定周期的任务&#xff0c;比如每周二0点1分执行一次。在《研发工程师玩转Kubernetes——非定时任务》中&#xff0c;我们介绍了单次执行的任务。现在我们只要对其清单稍作修改&#xff0c;就可以实现定时任务。 # wrk_cronjob.yaml apiVersion: batch/v1 ki…

【论文阅读】SeaD: End-to-end Text-to-SQL Generation with Schema-aware Denoising

【论文阅读】SeaD: End-to-end Text-to-SQL Generation with Schema-aware Denoising 文章目录 【论文阅读】SeaD: End-to-end Text-to-SQL Generation with Schema-aware Denoising1. 来源2. 介绍3. 模型3.0 问题定义3.1 采样公式3.2 带指针的 Transformer3.3 模式感知去噪&am…

低代码平台或零代码平台靠谱吗?15 年的老程序员来给大家剖析一下

提到低代码平台或者零代码平台靠谱吗&#xff1f;咱们首先得先认识一下低代码和零代码平台。 一、什么是低代码开发平台呢&#xff1f; 低代码的含义是少写代码并不是不写代码&#xff0c;面向的用户群体还是编程人员&#xff0c;传统的快速开发平台、在线开发平台、OA办公系统…

Python中Pandas库中的DataFrame数据结构创建举例

Python中Pandas库的DataFrame数据结构创建举例 DataFrame的数据结构是Python数据分析中重要应用数据类型。本文将重点介绍DataFrame的创建。 1.DataFrame的创建 创建DataFrame的方法使用pandas.DataFrame&#xff0c;向该方法传入字典即可创建DataFrame。 传入的字典的key对应E…

【HAL库】STM32F407----CAN通信----过滤器配置

【HAL库】STM32F407----CAN通信----基本原理 【HAL库】STM32F407----CAN通信----电路图 【HAL库】STM32F407----CAN通信----中断详解 【HAL库】STM32CubeMX开发----STM32F407----CAN通信实验 一、STM32F407----CAN过滤器----简介 在CAN协议里&#xff0c;报文的标识符不代表节…

纯vue 获取usb串口,实现电子秤的对接

说明&#xff1a;解决生产上过秤重量手动输入出错问题 效果图&#xff1a; 一&#xff1a;代码部分 1、创建一个名字为seriaport.js文件&#xff08;随便定义&#xff0c;为下面页面引入使用&#xff09; export default class MySerialPort {constructor() {this.state {po…

超级干货!前端入门先学什么?前端自学路线分享!

各位同学&#xff0c;下午好~之前给大家分享了前端岗位的面试题&#xff0c;小源能看的出来&#xff0c;还是有不少同学想入行前端的&#xff01;那除了会面试&#xff0c;还要有充足丰富的知识储备&#xff0c;这样才能拿下工作&#xff01; 好程序员今天就给大家整理了一份前…

C++进阶 —— set

目录 一&#xff0c;set介绍 二&#xff0c;set使用 一&#xff0c;set介绍 set是按照特定次序存储元素的关联式容器&#xff0c;元素不可重复&#xff1b;set中的元素不能在容器中修改(元素总是const)&#xff0c;但是可从容器中插入和删除它们&#xff1b;set中的元素总是按…

【Linux】进程间通信详解

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅 进程间通信介绍 什么是进程间通信&#xff1f; 进程间通信&#xff08;Interprocess communication&#xff0c;简称IPC&#xff09;就是让程序员能够协调不同的进…

【Apache 网页优化】

文章目录 一、Apahce 网页优化1、网页压缩2、网页缓存 二、Apachen的安全优化1、隐藏版本信息2、Apache 防盗链 一、Apahce 网页优化 1、网页压缩 1.检查是否安装 mod_deflate 模块 apachectl -t -D DUMP_MODULES | grep "deflate"2.如果没有安装mod_deflate 模块…

Java基础 流程控制语句

顺序结构 顺序结构就是程序从上到下逐行地执行。表达式语句都是顺序执行的。并且上一 行对某个变量的修改对下一行会产生影响。 public class StatementTest{public static void main(String[] args){int x 1;int y 2; System.out.println("x " x);System.out.p…

非科班自学一年心得,学弟学妹别瞎学了

大家好&#xff0c;我是帅地。 前两天我发了一篇亲学弟自学一年拿大厂 offer 的文章&#xff1a;非科班&#xff0c;帅地亲学弟自学一年拿到大厂offer了 不过那一篇只写了自己转行开发岗的心里变化&#xff0c; 这两天学弟又在知识星球发了一篇关于找工作的万字长文 说实话&…

ISO21434 项目网络安全管理

目录 一、概述 二、目标 三、输入 3.1 先决条件 3.2 进一步支持信息 四、要求和建议 4.1 网络安全责任 4.2 网络安全规划 4.3 裁剪 4.4 重用 4.5 非上下文组件 4.6 现成组件 4.7 网络安全案例&#xff08;Cybersecurity case&#xff09; 4.8 网络安全评估&#…

【惊叹】AI进步的速度太快,我们赶不上了?

文章目录 前言一、LoRA二、QLoRA1、环境准备2、推理就是直接 跑shscripts/generate.sh。3、前面的环境和数据都没问题了&#xff0c;运行scripts/generate.sh。 总结 前言 AI 领域的技术&#xff0c;真是隔一段时间就有一个新突破&#xff01; 全民都能训练大模型的时代&…

TypeScript算法题实战——剑指 Offer篇(3)

随着TypeScript的流行&#xff0c;越来越多的开发者开始使用TypeScript来解决算法问题。 在本文中&#xff0c;我们将使用TypeScript来解决剑指offer的算法题。这些问题涵盖了各种各样的主题&#xff0c;包括数组、字符串、链表、树、排序和搜索等。我们将使用TypeScript的强类…

【MySQL高级篇笔记 (中-索引的数据结构) 】

此笔记为尚硅谷MySQL高级篇部分内容 目录 一、索引及其优缺点 1、索引概述 2、优点 3、缺点 二、InnoDB中索引的推演 1、设计索引 1.一个简单的索引设计方案 2.InnoDB中的索引方案 2、常见索引概念 1. 聚簇索引 2. 二级索引&#xff08;辅助索引、非聚簇索引&#…

Node.js详解(一):基础知识

文章目录 一、Node.js介绍二、Node.js的优势三、Node.js的特点1、V8虚拟机2、事件驱动3、异步、非堵塞I/O 四、NodeJS带来的对系统瓶颈的解决方案1. 并发连接2. I/O阻塞 五、NodeJS的优缺点1、优点&#xff1a;2、缺点&#xff1a; 六、适合NodeJS的场景1、RESTful API2、统一W…

VMware、Ubuntu安装以及虚拟机复制粘贴问题

安装VMware 下载阿里云链接&#xff08;16 pro&#xff09;&#xff1a;VMware https://www.aliyundrive.com/s/ot9dhPNdSwC 安装&#xff1a;选一下安装地址&#xff0c;一直下一步即可。&#xff08;可能会要求重启电脑&#xff0c;重启即可&#xff09; 然后点击“许可证”…