【C++初阶】第11课—vector

文章目录

  • 1. 认识vector
  • 2. vector的遍历
  • 3. vector的构造
  • 4. vector常用的接口
  • 5. vector的容量
  • 6. vector的元素访问
  • 7. vector的修改
  • 8. vector<vector\<int\>>的使用
  • 9. vector的使用
  • 10. 模拟实现vector
  • 11. 迭代器失效
    • 11.1 insert插入数据内部迭代器失效
    • 11.2 insert插入数据外部迭代器失效
    • 11.3 erase删除数据迭代器失效
  • 12. 模拟实现resize
  • 13. 模拟实现vector的拷贝构造
  • 14. 模拟实现vector的赋值操作符重载
  • 15. 模拟实现reserve存在的坑
  • 16. 模拟实现vector初始化
  • 17. vector构造时容易出现的坑
  • 18. 模拟实现vector代码

1. 认识vector

  • vector是向量、矢量的意思
  • vector其实就是数据结构阶段学过的顺序表,行为看起来像指针一样的容器,底层不一定是用指针实现的,具体根据编译器的底层实现结构为准
  • vector的使用:vector<数据类型> 对象名

在这里插入图片描述


2. vector的遍历

在这里插入图片描述


3. vector的构造

在这里插入图片描述


  • 对于vector的析构,跟string类似,它会自动调用

4. vector常用的接口

在这里插入图片描述


  • vector上述的接口与string的接口并无二异

在这里插入图片描述


  • cbegin( )和cend( )的用法与begin和end类似,无非就是常量迭代器不能改变数据而已

5. vector的容量

在这里插入图片描述


在这里插入图片描述


  • 对于判空empty和请求缩容shrink_to_fit不再过多赘述,string里面都有讲到

6. vector的元素访问

在这里插入图片描述


在这里插入图片描述


  • at和下标访问操作符[ ]都是用来访问vector内的元素,区别是越界时下标操作符[ ]会报错,而at会抛出异常,关于这点string已经讲过,后续讲到捕获异常时可重温复习以加深理解

7. vector的修改

在这里插入图片描述


在这里插入图片描述


  • 其余的像swap用来交换两个vector对象,使用时可参考官方文档,大部分与string类模版中的用法类似

8. vector<vector<int>>的使用

  • vector<vector<int>>其实就是类似二维数组的用法,使用vector实例化出int类型的对象,再使用vector<vector<int>>实例化出vector<int>的对象

在这里插入图片描述


在这里插入图片描述


#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
//vector<vector<int>>的使用(杨辉三角)
size_t numRows = 0;
cin >> numRows; //行数
vector<vector<int>> vv(numRows);
//所有数设置为1
for (size_t i = 0; i < numRows; i++)
{
	vv[i].resize(i + 1, 1);
}
//中间元素为上面两个元素之和
for (size_t i = 2; i < numRows; i++)
{
	for (size_t j = 1; j < vv[i].size() - 1; j++)
	{
		vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
	}
}
//打印
for (size_t i = 0; i < numRows; i++)
{
	//打印前面的空格
	for (size_t k = 0; k < numRows - i - 1; k++)
	{
		cout << " ";
	}
	for (size_t j = 0; j < vv[i].size(); j++)
	{
		cout << vv[i][j] << " ";
	}
	cout << endl;
}
return 0;
}

9. vector的使用

  • 对于vector容器,也可以使用string类型,其插入string类型的数据如下

在这里插入图片描述


  • 关于vector和C++算法库的一些使用,以下先作为一个了解

在这里插入图片描述


10. 模拟实现vector

  • 之前讲述过,迭代器都是左闭右开的区间,对于begin指向第一个数,而end则指向最后一个数的下个位置
  • 因此对于vector的成员变量_start和_finish、_end_of_storage来讲,_finish就是指向有效数据的下个位置,_end_of_storage就指向容量的下个位置

在这里插入图片描述


在这里插入图片描述


  • 接下主要讲reserve扩容的坑,其余较容易实现

在这里插入图片描述


  • insert在pos位置插入字符
  • 注意:pos的类型是迭代器iterator,因为vector的成员变量是iterator类型,类似迭代器begin()和end()

在这里插入图片描述


  • 对于上述insert插入数据的代码,存在一个巨大隐患:迭代器失效的问题,接下来主要讲容器中的迭代器失效的问题

11. 迭代器失效

11.1 insert插入数据内部迭代器失效

在这里插入图片描述


  • 解决上面迭代器失效的方法:扩容后更新pos

在这里插入图片描述


11.2 insert插入数据外部迭代器失效

在这里插入图片描述


  • 即使是库里面实现的vector,对于insert插入数据也会出现迭代器失效的问题
  • 迭代器失效的根本原因就是扩容,扩容前后外部迭代器指向的是旧空间,而扩容后旧空间被释放,再访问就会报错
  • 因此对于insert插入数据后外部传参的迭代器,由于不同的平台结果可能不同,统一认为该迭代器失效
  • 解决办法:insert插入数据后更新迭代器

在这里插入图片描述


11.3 erase删除数据迭代器失效

在这里插入图片描述


在这里插入图片描述


  • 解决办法:在erase删除数据后即使更新迭代器it

在这里插入图片描述


  • 总结
  • 对于迭代器失效的问题,主要存在于容器插入和删除元素时,这里以vector为例,在insert插入数据和erase删除数据后,迭代器就处于失效的状态,这是因为插入数据扩容导致以及删除数据缩容导致的一系列问题
  • 对于不同的编译器,结果可能不同,并且vs对于迭代器失效的检查尤为严格,它会对失效的迭代器进行标记,如果尝试使用这些失效的迭代器,它就会报错
  • 因此统一认为容器插入数据和删除数据后迭代器处于失效的状态
  • 如果想继续使用失效的迭代器,解决办法就是在插入数据或删除数据前后根据实际情况及时更新迭代器,使迭代器正确指向对应的数据

12. 模拟实现resize

在这里插入图片描述


在这里插入图片描述


13. 模拟实现vector的拷贝构造

在这里插入图片描述


14. 模拟实现vector的赋值操作符重载

在这里插入图片描述


15. 模拟实现reserve存在的坑

  • reserve扩容的第一个坑

在这里插入图片描述


  • reserve扩容的第二个坑

在这里插入图片描述

  • 插入前四个字符串时没有问题,但是插入第5个字符串时,为什么会出现问题呢?
  • 因为插入第5个字符串时会扩容,reserve扩容中的memcpy其实就是一个浅拷贝,之前再C语言阶段实现过memcpy这个函数,它是一个字节一个字节拷贝的
  • 参考链接:memcpy的使用和模拟实现

在这里插入图片描述


在这里插入图片描述


  • 解决方案

在这里插入图片描述


16. 模拟实现vector初始化

  • C++11提供了vector初始化列表来进行初始化

在这里插入图片描述


  • inltializer_list是C++11设置一个模版类型
  • 其用法和之前创建数组有点类似

在这里插入图片描述


在这里插入图片描述


  • C++还提供了迭代器区间初始化

在这里插入图片描述


在这里插入图片描述


  • 当然数组也可以当做迭代器使用

在这里插入图片描述


17. vector构造时容易出现的坑

  • 用n个val值构造vector对象

在这里插入图片描述


在这里插入图片描述


  • 解决措施

在这里插入图片描述


18. 模拟实现vector代码

//模版
template <class T>
class vector
{
public:
	//迭代器
	typedef T* iterator;
	typedef const T* const_iterator;

	//构造函数
	vector()
	{}

	//初始化列表初始化
	vector(initializer_list<T> il)
	{
		reserve(il.size());
		for (auto& e : il)
		{
			push_back(e);
		}
		cout << "初始化列表初始化:" << endl;
	}

	//迭代器区间初始化
	//类模板函数的成员函数,也可以是函数模版
	template <class InputIterator>
	vector(InputIterator first, InputIterator last)
	{
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

	//vector的构造--->n个val
	vector(int n, const T& val = T())
	{
		resize(n, val);
	}

	vector(size_t n, const T& val = T())
	{
		resize(n, val);
	}

	//拷贝构造 
	vector(const vector<T>& v)
	{
		reserve(v.size());
		for (auto& e : v)
		{
			//this->push_back(e);
			push_back(e);
		}
	}

	//有效数据size
	size_t size() const
	{
		return _finish - _start;
	}

	//容量
	size_t capacity() const
	{
		return _end_of_storage - _start;
	}

	//begin
	iterator begin()
	{
		return _start;
	}

	//end
	iterator end()
	{
		return _finish;
	}

	//const begin
	const_iterator begin() const
	{
		return _start;
	}

	//const end
	const_iterator end() const
	{
		return _finish;
	}

	//resize改变有效数据个数
	void resize(size_t n, const T& val = T())
	{
		if (n < size())
		{
			_finish = _start + n;
		}
		else
		{
			reserve(n);
			while (_finish != _start + n)
			{
				*_finish = val;
				_finish++;
			}
		}
	}

	//扩容
	void reserve(size_t n)
	{
		if (n > capacity())
		{
			size_t oldsize = size();
			T* tmp = new T[n];
			/*memcpy(tmp, _start, sizeof(T) * size());*/

			for (size_t i = 0; i < oldsize; i++)
			{
				tmp[i] = _start[i];
			}
			delete[] _start;
			_start = tmp;
			_finish = oldsize + _start;
			_end_of_storage = n + _start;
		}
	}

	//尾插
	void push_back(const T& x)
	{
		if (_finish == _end_of_storage)
		{
			reserve(capacity() == 0 ? 4 : 2 * capacity());
		}
		*_finish = x;
		_finish++;
	}

	//尾删
	void pop_back()
	{
		assert(_finish > _start);
		_finish--;
	}

	//重载下标操作符[]
	T& operator[](size_t i)
	{
		return _start[i];
	}

	//赋值操作符---第一种写法
	//vector<T>& operator=(const vector<T>& v)
	//{
	//	if (this != &v)
	//	{
	//		delete[] _start;
	//		_start = _finish = _end_of_storage = nullptr;
	//		reserve(v.size());
	//		for (auto& e : v)
	//		{
	//			//this->push_back(e);
	//			push_back(e);
	//		}
	//	}
	//	return *this;
	//}


	void swap(vector<T> v)
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_end_of_storage, v._end_of_storage);
	}
	//赋值操作符---第二种写法
	vector<T>& operator=(const vector<T>& v)
	{
		swap(v);
		return *this;
	}

	//任意位置插入,insert插入数据后迭代器失效
	void insert(iterator pos, const T& x)
	{
		assert(pos >= _start);
		assert(pos <= _finish);

		//满了扩容
		if (_finish == _end_of_storage)
		{
			size_t len = pos - _start;
			reserve(capacity() == 0 ? 4 : 2 * capacity());
			pos = _start + len;
		}
		//挪动数据
		iterator end = _finish - 1;
		while (end >= pos)
		{
			*(end + 1) = *end;
			--end;
		}
		//插入数据
		*pos = x;
		++_finish;
	}

	//erase删除数据
	iterator erase(iterator pos)
	{
		assert(pos >= _start);
		assert(pos < _finish);

		iterator begin = pos + 1;
		while (begin < _finish)
		{
			*(begin - 1) = *begin;
			++begin;
		}
		--_finish;

		return pos;
	}

	//析构
	~vector()
	{
		delete[] _start;
		_start = _finish = _end_of_storage = nullptr;
	}
private:
	iterator _start = nullptr;
	iterator _finish = nullptr;
	iterator _end_of_storage = nullptr;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT 结束语设计 以nanogpt为例

GPT 结束语设计 以nanogpt为例 目录 GPT 结束语设计 以nanogpt为例 1、简述 2、分词设计 3、结束语断点 1、简述 在手搓gpt的时候&#xff0c;可能会遇到一些性能问题&#xff0c;即关于是否需要全部输出或者怎么节约资源。 在输出语句被max_new_tokens 限制&#xff0c…

PTMD2.0-疾病相关的翻译后修饰数据库

翻译后修饰&#xff08;PTMs&#xff0c;post-translational modifications&#xff09;通过调节蛋白质功能参与了几乎所有的生物学过程&#xff0c;而 PTMs 的异常状态常常与人类疾病相关。在此&#xff0c;PTMD 2.0展示与疾病相关的 PTMs 综合数据库&#xff0c;其中包含 93 …

ArcGIS10.2 许可License点击始终启动无响应的解决办法及正常启动的前提

1、问题描述 在ArcGIS License Administrator中&#xff0c;手动点击“启动”无响应&#xff1b;且在计算机管理-服务中&#xff0c;无ArcGIS License 或者License的启动、停止、禁止等均为灰色&#xff0c;无法操作。 2、解决方法 ①通过cmd对service.txt进行手动服务的启动…

spring框架之IoC学习与梳理(1)

目录 一、spring-IoC的基本解释。 二、spring-IoC的简单demo&#xff08;案例&#xff09;。 &#xff08;1&#xff09;maven-repository官网中找依赖坐标。 &#xff08;2&#xff09;.pom文件中通过标签引入。 &#xff08;3&#xff09;使用lombok帮助快速开发。 &#xff…

系统架构设计师教材:信息系统及信息安全

信息系统 信息系统的5个基本功能&#xff1a;输入、存储、处理、输出和控制。信息系统的生命周期分为4个阶段&#xff0c;即产生阶段、开发阶段、运行阶段和消亡阶段。 信息系统建设原则 1. 高层管理人员介入原则&#xff1a;只有高层管理人员才能知道企业究竟需要什么样的信…

基于STM32单片机设计的宠物喂食监控系统

1. 项目开发背景 随着宠物数量的增加&#xff0c;尤其是人们对宠物的养护需求日益增多&#xff0c;传统的人工喂养和管理方式难以满足现代养宠生活的需求。人们越来越希望通过智能化手段提高宠物养护的质量和效率&#xff0c;特别是对于宠物喂食、饮水、温湿度控制等方面的智能…

帕金森患者:科学锻炼,提升生活质量

帕金森病&#xff0c;作为一种常见的神经系统退行性疾病&#xff0c;给患者的日常生活带来了诸多挑战。然而&#xff0c;通过科学的锻炼&#xff0c;患者不仅可以在一定程度上缓解症状&#xff0c;还能提升生活质量。本文将详细介绍帕金森患者应该进行的几种关键锻炼&#xff0…

GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比

GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比 目录 GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于GA-CNN-LST…

redis 实践与扩展

文章目录 前言一、springboot整合redis1、jedis1.1、单点模式1.2、哨兵模式1.3 集群模式1.4、关于jedis线程不安全的验证 2、lettuce(推荐)2.1、单点模式2.2、哨兵模式2.3、集群模式 3、RedisTemplate config 二、redis常用知识点1、缓存数据一致性2、缓存雪崩3、缓存击穿4、缓…

積分方程與簡單的泛函分析7.希爾伯特-施密特定理

1)def函數叫作"由核生成的(有源的)" 定义: 设 是定义在区域上的核函数。 对于函数,若存在函数使得, 则称函数是“由核生成的(有源的)”。 这里的直观理解是: 函数的“来源”可以通过核函数 与另一个函数的积分运算得到。 在积分方程理论中,这种表述常…

RH850F1KM-S4-100Pin_ R7F7016453AFP MCAL PWM 测试

1、PortPin配置 2、PwmChannel配置 4、PwmComplexDriverInit 配置注意事项 此参数指定通道是否初始化并由复杂驱动程序使用。 True:通道将被初始化并由复杂驱动程序使用。False:通道不会被初始化并被复杂驱动程序使用。

Spring Boot Starter介绍

前言 大概10来年以前&#xff0c;当时springboot刚刚出现并没有流行&#xff0c;当时的Java开发者们开发Web应用主要是使用spring整合springmvc或者struts、iBatis、hibernate等开发框架来进行开发。项目里一般有许多xml文件配置&#xff0c;其中配置了很多项目中需要用到的Be…

【科研建模】Pycaret自动机器学习框架使用流程及多分类项目实战案例详解

Pycaret自动机器学习框架使用流程及项目实战案例详解 1 Pycaret介绍2 安装及版本需求3 Pycaret自动机器学习框架使用流程3.1 Setup3.2 Compare Models3.3 Analyze Model3.4 Prediction3.5 Save Model4 多分类项目实战案例详解4.1 ✅ Setup4.2 ✅ Compare Models4.3 ✅ Experime…

CY T 4 BB 5 CEB Q 1 A EE GS MCAL配置 - MCU组件

1、ResourceM 配置 选择芯片信号: 2、MCU 配置 2.1 General配置 1) McuDevErrorDetect: - 启用或禁用MCU驱动程序模块的开发错误通知功能。 - 注意:采用DET错误检测机制作为安全机制(故障检测)时,不能禁用开发错误检测。2) McuGetRamStateApi - enable/disable th…

【论文阅读】RAG-Reward: Optimizing RAG with Reward Modeling and RLHF

研究背景 研究问题&#xff1a;这篇文章要解决的问题是如何优化检索增强生成&#xff08;RAG&#xff09;系统&#xff0c;特别是通过奖励建模和人类反馈强化学习&#xff08;RLHF&#xff09;来提高大型语言模型&#xff08;LLMs&#xff09;在RAG任务中的效果。研究难点&…

关于WPF中ComboBox文本查询功能

一种方法是使用事件&#xff08;包括MVVM的绑定&#xff09; <ComboBox TextBoxBase.TextChanged"ComboBox_TextChanged" /> 然而运行时就会发现&#xff0c;这个事件在疯狂的触发&#xff0c;很频繁 在实际应用中&#xff0c;如果关联查询数据库&#xff0…

java求职学习day15

多线程 1 基本概念 1.1 程序和进程的概念 &#xff08;1&#xff09;程序 - 数据结构 算法&#xff0c;主要指存放在硬盘上的可执行文件。 &#xff08;2&#xff09;进程 - 主要指运行在内存中的可执行文件。 &#xff08;3&#xff09;目前主流的操作系统都支持多进程&a…

2025年数学建模美赛:A题分析(1)Testing Time: The Constant Wear On Stairs

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…

2024年终总结:技术成长与突破之路

文章目录 前言一、技术成长&#xff1a;菜鸟成长之路1. 学习与实践的结合2. 技术分享与社区交流 二、生活与事业的平衡&#xff1a;技术之外的思考1. 时间管理与效率提升2. 技术对生活的积极影响 三、突破与展望&#xff1a;未来之路1. 技术领域的突破2. 未来规划与目标 四、结…

go入门Windows环境搭建

简介 Go 即 Golang&#xff0c;是 Google 公司 2009 年 11 月正式对外公开的一门编程语言。 根据 Go 语言开发者自述&#xff0c;近 10 多年&#xff0c;从单机时代的 C 语言到现在互联网时代的 Java&#xff0c;都没有令人满意的开发语言&#xff0c;而 C往往给人的感觉是&a…