C++ list介绍(迭代器失效)

news2024/11/20 8:27:20

一、常用接口

reverse逆置
sort排序(默认升序)
仿函数greater<int>
merge合并,可以全部合并,也可以一部分合并
unique:去重(先排序,再去重)
remove:删除e值,而不是erase的pos位置删
splice(粘接):其实就是transform(转移)
把某个位置i,转移到当前链表的某个position之前


list的sort效率很低,底层用归并,但是数据访问很低,因为是链表
vectror的sort更好一些,因为是连续的空间

二、迭代器封装问题


原生指针就是天生的迭代器(但是前提是物理空间是连续的)
为什么??
因为解引用就是该数据,++就是下一个数据
但是如果空间是不连续的就会出问题

例如list的原生指针就不能作为迭代器,因为不符合预期
因为list的原生指针式list*,但是list*++是错误的,因为不是连续的空间
解引用list*++,就是在原来地址位置,向后移动一个list类型大小的距离,指向该位置
但是因为不是连续的空间,所以,移动后的list*并不是下一个节点的地址
那怎么办呢?
改造一下
我们用一个类去封装这个原生指针,然后用这个类去控制这个原生指针
重载++list为移动到下一个节点的位置
需要处理的是这个部分

用类封装一个原生指针,这个原生指针也是一个模板
然后重定义这个原生指针为iterator
也就是说,这个itrator就是一个原生指针
这个原生指针也是一个模板
那么,当我们传入任意类型时,原生指针模板就会自动推导出其对应的指针
只是这个指针取了一个别名,叫做iterator,即迭代器
这就充分利用了类型的内涵
也就是说此处的迭代器底层还是一个指针
但是这个指针的行为不符合我们的预期
所以我们需要封装,重载行为

指针是内置类型
前置++和后置++是如何判断的呢?
因为函数重载只看参数列表,返回值不影响
所以,在后置++的重载参数列表加一个占位参数,int
这样就会区别两个函数
迭代器比较:就是比较指针,指针就是地址。地址相等,迭代器相等,否则不等
iterator的特点是不管底层是什么

三、list模拟实现(原码)

insert:
参数为iterator
找到当前的节点
记录前,后,插入即可

erase:参数pos也是iterator指针
删除节点后,当前节点的指针1iterator失效
所以要更新iterator
返回下一个节点的指针

pop_back:删除--end()
end是head,是头节点

resize:尾删和尾插

#pragma once
#include<assert.h>
#include<iostream>
using namespace std;


namespace myspace
{

	//节点
	template <class T>
	struct list_node
	{
		list_node(const T& val = 0)
			:_date(val)
			, _next(nullptr)
			, _prev(nullptr)
		{
		}


		list_node<T>* _next;
		list_node<T>* _prev;
		T _date;
	};



	//迭代器
	template <class T, class Ref, class ptr>
	struct list_iterator
	{
		typedef list_node<T> node;
		typedef list_iterator<T, Ref, ptr> self;//模板推导


		list_iterator(node* node)
			:_node(node)
		{
		}

		//++it
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//it++
		self& operator++(int)
		{
			self tmp = _node;
			_node = _node->_next;
			return tmp;
		}


		//--it
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		//it--
		self& operator--(int)
		{
			self tmp = _node;
			_node = _node->_prev;
			return  tmp;
		}

		//operator
		T& operator*()
		{
			return _node->_date;
		}

		T* operator->()
		{
			return &_node->_date;
		}

		bool operator==(const self& it)
		{
			return _node == it._node;
		}

		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		node* _node;
	};

	//反向迭代器
	template <class T, class Ref, class ptr>

	struct list_reverse_iterator
	{
		typedef list_node<T> node;
		typedef list_reverse_iterator<T, Ref, ptr> self;//模板推导


		list_reverse_iterator(node* node)
			:_node(node)
		{
		}

		//++it
		self& operator++()
		{
			_node = _node->_prev;
			return *this;
		}
		//it++
		self& operator++(int)
		{
			self tmp = _node;
			_node = _node->_prev;
			return tmp;
		}


		//--it
		self& operator--()
		{
			_node = _node->_next;
			return *this;
		}

		//it--
		self& operator--(int)
		{
			self tmp = _node;
			_node = _node->_next;
			return  tmp;
		}

		//operator
		T& operator*()
		{
			node* tmp = _node->_prev;
			_node = _node->_prev;
			return tmp->_date;
		}

		T* operator->()
		{
			node* tmp = _node->_prev;
			_node = _node->_prev;
			return &tmp->_date;
		}

		bool operator==(const self& it)
		{
			return _node == it._node;
		}

		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		node* _node;
	};



	//一般对象的iterator和const对象的const_iterator
	//由于两者对应的实现不同,因此,一般的方式是写两个类
	//但是,二者的区别只有*引用和->引用两者的不同
	//所以,如果要书写两个类,显的臃肿
	//所以,可以使用模板
	//在需要的地方使用模板推导

	template <class T>
	class list
	{
		typedef list_node<T> node;
	public:
		typedef list_iterator<T, T&, T*> iterator;//一般对象的iterator
		typedef list_iterator<T, const T&, const T*> const_iterator;//const对象的iterator
		typedef list_reverse_iterator<T, T&, T*> reserve_iterator;//reserve_iterator


		void empty_init()
		{
			node* newnode = new node;
			newnode->_next = newnode;
			newnode->_prev = newnode;
			this->_head = newnode;
			_size = 0;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		bool empty()
		{
			return size() == 0;
		}

		size_t size()
		{
			return _size;
		}


		list()
		{
			empty_init();
		}

		//lt1(lt2)
		//需要重新搞出一个新的list
		//(this指针就是lt1)
		list(const list<T>& lt)
		{
			empty_init();
			for (auto& e : lt)
			{
				push_back(e);
			}
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}


		iterator begin()
		{
			return _head->_next;
		}
		iterator end()
		{
			return _head;
		}

		const_iterator begin() const
		{
			return _head->_next;
		}
		const_iterator end() const
		{
			return _head;
		}


		reserve_iterator rbegin()
		{
			return _head;
		}
		reserve_iterator rend()
		{
			return _head->_next;
		}

		//void swap(const list<T>& lt)
		//{
		//	std::swap(_head,lt._head);
		//	std::swap(lt._size, _size);
		//}


		void push_back(const T& val)
		{
			insert(_head, val);
		}

		void push_front(const T& val)
		{
			insert(begin(), val);
		}

		void pop_back()
		{
			erase(_head->_prev);
		}

		void pop_front()
		{
			erase(begin());
		}

		void insert(iterator pos, const T& val)
		{

			node* tmp = new node(val);
			node* next = pos._node;
			node* prev = pos._node->_prev;
			prev->_next = tmp;
			tmp->_prev = prev;
			next->_prev = tmp;
			tmp->_next = next;
			++_size;
		}

		iterator erase(iterator pos)
		{
			if (_size == 0)
				return nullptr;

			node* cur = pos._node;
			node* next = cur->_next;
			node* prev = cur->_prev;
			next->_prev = prev;
			prev->_next = next;

			delete cur;
			pos = nullptr;

			--_size;
			return  next;
		}



	private:
		node* _head;
		size_t _size;
	};

	//打印const对象
	void print(const list<int>& clt)
	{
		list<int>::const_iterator it = clt.begin();
		while (it != clt.end())
		{
			cout << *it << " ";
		}
		cout << endl;

	}

	//正常的增删改
	void test1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		lt.insert(lt.begin(), 10);
		//lt.erase(lt.begin());
		lt.pop_back();
		lt.pop_back();
		lt.pop_back();
		lt.pop_back();
		lt.pop_back();
		lt.pop_back();

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

	}


	void test2()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		lt.clear();

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << lt.size() << endl;
		cout << endl;
	}



	void test3()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		cout << lt.empty() << endl;

	}


	void test4()
	{
		list<int>  lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);

		//list<int>::const_iterator it = lt.begin();
		//while (it != lt.end())
		//{
		//	cout << *it << " ";
		//	++it;
		//}

		cout << endl;
		cout << lt.empty() << endl;

	}


	void print_list(const list<int>& clt)
	{
		//const对象的迭代器
		//const_iterator迭代器是一个单独的对象
		//为了区别于一般对象,单独搞了一个const_iterator类
		//这个const_iterator类的目的在于,可以正常进行遍历,但是不能对内部的内容进行修改
		//因为实现方法不同,一个类无法实现,因此可以考虑使用模板
		list<int>::const_iterator it = clt.begin();
		while (it != clt.end())
		{
			//*it += 10;
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}


	void test5()
	{
		list<int>  lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		lt.push_front(100);
		//lt.erase(lt.end());
		lt.pop_back();
		lt.pop_back();
		lt.pop_back();
		lt.pop_front();

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}


	void test6()
	{
		list<int>  lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		list<int> lt2(lt);
		list<int> lt3;
		lt3.push_back(10);
		lt3.push_back(11);
		lt3.push_back(12);
		lt3.push_back(13);
		//lt3.swap(lt2);



		list<int>::iterator it = lt3.begin();
		while (it != lt3.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

	}

	void test7()
	{
		list<int>  lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);

			list<int>::reserve_iterator rlt = lt.rbegin();
			while (rlt != lt.rend())
			{
				cout << *rlt << " ";
			}
			cout << endl;
		}



	}






四、相关细节

什么时候用struct,什么时候用class?
数据都是共有的时候就可以使用struct

模拟实现的时候,需要定义一个自己的命名空间,防止和库内冲突
将指针类型设置为模板,因为要支持不同数据的list

typedef ListNode<T> node #意为将节点设置为模板
但是,为了便于理解,我们编写代码的时候,还是使用node,便于理解
但是实际上,这个node其实是一个模板,我们用了一个typedef宏替换实现的
创建一个新节点的时候,也是,直接new node
这样就会直接开辟一个新空间节点出来,一个模板类型的空间节点

模板的理解:很简单
就是多了一个template<class T>而已
然后将对应的东西设置为T,再typedef就是了
例如:我要将list的节点设置为模板,那么:
typedef ListNode<T> node
节点设置为模板:ListNode<T>
换名字:typedef ListNode<T> node
不要把模板看的这么复杂
也不要吧typedef看的太复杂

list中at会检查越界,[]不会检查

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

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

相关文章

Hive SQL Join连接操作用法详解

Hive SQL Join连接操作 1.Hive join语法规则 基本语法&#xff1a; SELECT column_list FROM table1 JOIN table2 ON table1.column_name table2.column_name;JOIN类型&#xff1a; 在JOIN语句中&#xff0c;你可以使用不同类型的JOIN操作&#xff0c;包括INNER JOIN、LEFT O…

水面垃圾清理机器人的视觉算法研究

卷积神经网络是一种分层的数据表示模型&#xff0c;通常由数据输入层、卷积层、池化层、 非线性激活函数、全连接层以及输出结果预测层等组成&#xff0c;其中卷积层、池化层和非线 性激活函数是卷积神经网络中的重要组成部分。此外&#xff0c;有些模型会增加其他的层(归一 化…

C#贪吃蛇

C#贪吃蛇 文章目录 Program.csText1Game.csISceneUpdate.csText2BeginScene.csBegionOrEndScene.csEndScene.csGameScene.csText3GameObject.csIDraw.csPosition.csText4Food.csSnakeBody.csWall.csText5Map.csText6Snake.csProgram.cs using 贪吃蛇.Text1;Game game = new Ga…

pinia持久化出现store和storage的数据不一致的问题

问题描述 突然发现menu的store异常&#xff0c;pinia中查看到store数据正确&#xff0c;但是localstorage中的数据始终没有同步&#xff0c;但user的store没问题&#xff0c;具体如下&#xff1a; menu的store&#xff1a; user的store&#xff1a; 问题原因 进入系统…

[嵌入式系统-72]:RT-Thread-组件:单元测试框架utest

目录 utest 测试框架 ​编辑 测试用例定义 测试单元定义 utest 应用框图 2. utest API assert 宏 测试单元函数运行宏 测试用例导出宏 测试用例 LOG 输出接口 3. 配置使能 4. 应用范式 5. 测试用例运行要求 6. 运行测试用例 测试结果分析 7. 测试用例运行流程 …

mysql中varchar与bigint直接比较会导致精度丢失以至于匹配到多行数据

在mysql中&#xff0c;我们都知道如果一个索引字段使用了函数或者计算那么查询的时候索引会失效&#xff0c;可是我相信在联表的时候我们只会关注两个表关联字段是否都创建了索引&#xff0c;却没有关注过这两个字段的类型是否一致&#xff0c;如果不一致的话索引是会失效的&am…

uni-app实战在线教育类app开发

随着移动互联网的快速发展&#xff0c;教育行业也在不断向在线化、数字化方向转型。开发一款功能丰富、用户体验优秀的在线教育类 App 对于满足学习者需求、促进教育行业的发展至关重要。本文将介绍如何利用 Uni-App 进行在线教育类 App 的开发&#xff0c;让您快速上手&#x…

Python 全栈体系【四阶】(三十九)

第五章 深度学习 八、目标检测 3. 目标检测模型 3.2 YOLO 系列 3.2.4 YOLOv4&#xff08;2020 年 4 月&#xff09; YOLOv4 将最近几年 CV 界大量的研究成果集中在一套模型中&#xff0c;从检测速度、精度、定位准确率上有了明显改善&#xff08;相对于 YOLOv3&#xff0c…

前端项目加载离线的百度地图,利用工具进行切指定区域的地图影像,自定义图层getTilesUrl

百度地图在开发中我们经常使用&#xff0c;但是有些项目是需要在内网进行&#xff0c;这时候我们不得不考虑项目中一些功能需要请求外网静态资源&#xff0c;比如百度地图。只有把包下载到本地&#xff0c;才能让静态资源文件的正常的访问。 目录 获取百度地图开发秘钥 引入在…

yolov8任务之目标检测

对象检测 对象检测是一项涉及识别图像或视频流中对象的位置和类别的任务。对象检测器的输出是一组包围图像中对象的边界框&#xff0c;以及每个框的类标签和置信度分数。当您需要识别场景中感兴趣的对象&#xff0c;但不需要确切知道对象在哪里或其确切形状时&#xff0c;对象检…

网络安全之ACL

ACL&#xff1a;访问控制列表——控制列表&#xff08;策略列表&#xff09;&#xff0c;是一个控制工具。 功能&#xff1a;&#xff01;、定义感兴趣路由&#xff08;控制层面&#xff09;。2、定义感兴趣流量&#xff08;数据层面&#xff09;。 例如&#xff1a; 假设在该…

AI换脸原理(7)——人脸分割参考文献TernausNet: 源码解析

1、介绍 这篇论文相对来说比较简单,整体是通过使用预训练的权重来提高U-Net的性能,实现对UNet的改进。该方法也是DeepFaceLab官方使用的人脸分割方法。在介绍篇我们已经讲过了UNet的网络结构和设计,在进一步深入了解TernausNet之前,我们先简单回顾下UNet。 U-Net的主要结构…

Django Admin后台管理:高效开发与实践

title: Django Admin后台管理&#xff1a;高效开发与实践 date: 2024/5/8 14:24:15 updated: 2024/5/8 14:24:15 categories: 后端开发 tags: DjangoAdmin模型管理用户认证数据优化自定义扩展实战案例性能安全 第1章&#xff1a;Django Admin基础 1.1 Django Admin简介 Dj…

【爬虫】爬取A股数据写入数据库(二)

前几天有写过一篇 【爬虫】爬取A股数据写入数据库&#xff08;一&#xff09;&#xff0c;现在继续完善下&#xff0c;将已有数据通过ORM形式批量写入数据库。 2024/05&#xff0c;本文主要内容如下&#xff1a; 对东方财富官网进行分析&#xff0c;并作数据爬取&#xff0c;使…

ORA-28575: unable to open RPC connection to external procedure agent

环境&#xff1a; Oracle 11.2.0.4x64 RAC AIX6.1版本SDE for aix oracle11g版本10.0 x64 sde配置情况如下&#xff1a; 检查oracle和grid用户下的$ORACLE_HOME/hs/admin/extproc.ora文件均包含有如下&#xff1a; SET EXTPROC_DLLSANY 两个节点sde下的user_libraries都正常…

npm安装指定版本,npm删除依赖,卸载依赖

安装指定版本 npm中安装指定的版本号&#xff0c;格式为 ‘包名版本号’ npm install 包名称版本号 --save 例如安装jquery: npm install jquery3.0.0 --save在package.json里面可以看到对应的包&#xff1a; "jquery": "^3.0.0"注意&#xff1a;已有…

Duplicate File Finder Pro for Mac激活版:重复文件清理软件

在繁杂的文件管理中&#xff0c;你是否曾为重复文件而烦恼&#xff1f;Duplicate File Finder Pro for Mac&#xff0c;正是你不可或缺的得力助手。这款专业级工具&#xff0c;能够迅速扫描并定位Mac系统中的重复文件&#xff0c;让你的存储空间恢复清爽。 通过强大的算法支持&…

天诚人脸物联网锁+网约房管理系统为智慧酒店、民宿管理赋能

随着互联网技术的发展&#xff0c;“网约房”逐渐步入受众视野&#xff0c;在改变旅客入住模式和生活方式的同时&#xff0c;为旅客旅游住宿创造了新的选择&#xff0c;也为拥有冗余房间资源的房东提供了新的营收路径。但是&#xff0c;网约房的管理问题频发&#xff0c;需要数…

Android 右键 new AIDL 无法选择

提示 (AIDL File)Requires setting the buildFeatures.aidl to true in the build file&#xff09; 解决方式&#xff1a; 在app的build.gradl中 adnroid{} 添加&#xff1a; buildFeatures{aidl true}

SpringCloud Alibaba Sentinel 修改Dashboard用户名和密码

目录 一、下载Sentinel的Jar包 二、在启动时修改用户名和密码的命令 三、测试登录成功 在网上找到了一大堆文章&#xff0c;没一个有用的&#xff0c;最终还是通过不断测试找到了这个方法。 一、下载Sentinel的Jar包 Releases alibaba/Sentinel GitHub 二、在启动时修改…