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

一、常用接口

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.mfbz.cn/a/605721.html

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

相关文章

Django之rest_framework(六)

一、GenericViewSet类的使用 继承自GenericAPIView,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于视图的开发 1.1、代码 from rest_framework.viewsets import GenericViewSet from rest_framework.response import Response from rest_framework …

基于Springboot+Vue+Java的校园资料分享平台

&#x1f49e; 文末获取源码联系 &#x1f649; &#x1f447;&#x1f3fb; 精选专栏推荐收藏订阅 &#x1f447;&#x1f3fb; &#x1f380;《Java 精选实战项目-计算机毕业设计题目推荐-期末大作业》&#x1f618; 更多实战项目~ https://www.yuque.com/liuyixin-rotwn/ei3…

【前端热门框架【vue框架】】——对组件进行更加简洁合理的处理和解释(一)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;程序员-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

css mix-blend-mode 层叠样式属性各类效果

官方给出的定义是&#xff1a;mix-blend-mode css 属性描述了元素的内容应该与元素的直系父元素的内容和元素的背景如何混合。 通俗来讲&#xff0c;就是一张图片跟它的父级元素背景色的融合方式。 大致分为以下16种&#xff1a; mix-blend-mode: normal; mix-blend-mode: m…

QT--day3

1、mywidget.h #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> #include<QIcon> //图标类 #include<QLabel> //标签类 #include<QMovie> //动图类 #include<QLineEdit> //行编辑器类 #include<QPushButton> //按钮类 #include…

美团二面:SpringBoot读取配置优先级顺序是什么?

引言 Spring Boot作为一种轻量级的Java应用程序框架&#xff0c;以其开箱即用、快速搭建新项目的特性赢得了广大开发者的青睐。其核心理念之一就是简化配置过程&#xff0c;使开发者能够快速响应复杂多变的生产环境需求。为了实现这一点&#xff0c;Spring Boot支持丰富的外部…

智慧旅游推动旅游服务智慧化转型:借助智能科技的力量,实现旅游资源的精准匹配和高效利用,为游客提供更加便捷、舒适的旅游环境

目录 一、引言 二、智慧旅游的定义与特点 &#xff08;一&#xff09;智慧旅游的定义 &#xff08;二&#xff09;智慧旅游的特点 三、智能科技在旅游服务中的应用 &#xff08;一&#xff09;大数据分析助力旅游决策 &#xff08;二&#xff09;人工智能实现个性化推荐…

【C++】map和set的基础详解

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【使用ChatGPT的API之前】OpenAI API提供的可用模型

文章目录 一. ChatGPT基本概念二. OpenAI API提供的可用模型1. InstructGPT2. ChatGPT3. GPT-4 三. 在OpenAI Playground中使用GPT模型-ing 在使用GPT-4和ChatGPT的API集成到Python应用程序之前&#xff0c;我们先了解ChatGPT的基本概念&#xff0c;与OpenAI API提供的可用模型…

SpringBoot Actuator未授权访问漏洞的解决方法

1. 介绍 Spring Boot Actuator 是一个用于监控和管理 Spring Boot 应用程序的功能模块。它提供了一系列生产就绪的功能&#xff0c;帮助你了解应用程序的运行状况&#xff0c;以及在运行时对应用程序进行调整。Actuator 使用了 Spring MVC 来暴露各种 HTTP 或 JMX 端点&#x…

WOA-SVM多变量分类预测|基于鲸鱼优化算法的支持向量机|Matalb

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

stm32f103zet6_RTC_1_介绍

RTC简介 实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器&#xff0c;在相应软件配置下&#xff0c;可 提供时钟日历的功能。 修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域&#xff0c;即在系统复…

工采电子国产D类音频放大器iML6602可以替代TPA3118

iML6602是一款高集成度、高效率的双声道D类音频功率放大器&#xff1b;支持BTL和PBTL两种模式输出&#xff0c;供电电压范围4.5V ~ 26V&#xff1b;双通道BTL模式下输出功率 230W&#xff08;8Ω&#xff0c;24V&#xff0c;THDN0.1%&#xff09;单通道PBTL模式下可以输出60W&a…

Python中的函数定义(def)详解

Python中的函数定义&#xff08;def&#xff09;详解 在编程语言中&#xff0c;函数是组织代码的一种方式&#xff0c;它们可以帮助我们将复杂的程序拆分为简单、易管理的部分。在Python中&#xff0c;函数的定义使用def关键字。 什么是函数&#xff1f; 函数是一段完成特定…

虚拟串口调试(Windows)

在单片机和嵌入式设备开发过程中&#xff0c;我们有时需要对程序的串口进行调试&#xff0c;但是身边又恰好没有硬件设备&#xff0c;此时&#xff0c;我们可以通过虚拟串口来实现模拟本地端口&#xff0c;方便调试。 软件安装 VSPD虚拟串口工具 下载VSPD软件&#xff1a;百…

django和vue开发的前后端分离网站怎么部署到服务器上,django和vue前后端分离网站怎么通过宝塔部署

提示&#xff1a;如果看完全部教程后仍然部署不成功&#xff0c;可以联系作者 一、提前准备 想要把django vue 前后端分离网站部署到服务器上&#xff0c;有一些提前准备的东西 1、备案域名&#xff08;域名必须备案&#xff09; 这里需要解析两个域名&#xff0c;一个前端&…

【数据结构|C语言版】栈和队列

前言1. 栈1.1 栈的概念和性质1.2 顺序栈1.3 链栈1.4 共享栈 2. 队列2.1 队列的概念和性质2.2 循环队列2.3 链式队列2.4 双端队列 3. 例题精选3.1 有效的括号3.2 用队列实现栈2.4 用栈实现队列3.4 设计循环队列3.5 参考答案 结语 #include<GUIQU.h> int main { 上期回顾: …

浏览器控制台console常用命令小结

chrome调试工具的Console对象相信很多人使用过&#xff0c;熟练的Web开发人员会经常使用 console.log() 在其代码中打印消息和调试问题&#xff0c;实际上还有很多很有用的功能和技巧&#xff0c;善用之可以极大提高Web开发&#xff0c;网站调优的效率&#xff01; 这里我们总结…

Ansible---Playbook剧本

文章目录 Playbook案例1 Playbook剧本基本用法案例2 Playbook剧本定义、引用变量案例3.when条件判断迭代剧本Roles 模块 Playbook Tasks&#xff1a;任务是 Playbooks 的核心&#xff0c;它们是 Playbook 中的一项指令&#xff0c;告诉 Ansible 在远程主机上执行什么操作。每个…
最新文章