list模拟实现--用节点封装的迭代器问题

news2024/9/23 13:30:35

目录

一、list的使用

1.1list的构造

1.2list的iterator

​编辑

1.3 list的capacity

1.4 list的element access

​编辑

1.5list的mdifiers

 ​编辑

二、list的迭代器失效问题

三、list的模拟实现

3.1定义一个节点类

3.2用节点去封装迭代器

编译器对->的优化问题 

 ​编辑

Ref和Ptr

3.3list基本功能的实现

四、vector和list的比较

4.1vector

4.2list


一、list的使用

1.1list的构造

1.2list的iterator

1.3 list的capacity

1.4 list的element access

1.5list的mdifiers

 

二、list的迭代器失效问题

list的底层是双向带头循环链表,在实现插入功能的时候是一边扩容一边插入,且都是在原空间上进行操作的,因此list的插入不存在迭代器失效问题;但list的删除就会使该节点位置的迭代器失效,其他位置的迭代器不受影响,如果要解决这个问题,仍然是用迭代器去接收返回值。 

三、list的模拟实现

3.1定义一个节点类

//节点
template<class T>
struct list_node
{
	list_node<T>* _prev;
	list_node<T>* _next;
	T _val;

	list_node(const T& x = T())
		:_prev(nullptr)
		,_next(nullptr)
		,_val(x)
	{}

};

节点类就相当于c语言中的BuyNewNode() 

3.2用节点去封装迭代器

因为list的底层结构是不连续的,指向节点的指针++不一定是list下一个位置的节点,因此不能使用原生指针来作为list的迭代器。这里的解决办法是用节点指针(原生指针)去封装迭代器,在这个迭代器类的内部去模拟实现原生指针的功能,即用运算符重载实现适配于list的++ -- != == * ->等操作

//用节点(自定义类型)封装的迭代器
//typedef _list_iterator<T,T&,T*> iterator;
//typedef _list_iterator<T, const T&, const T*> const_iterator;
template<class T,class Ref,class Ptr>
struct _list_iterator
{
	typedef list_node<T> Node;
	typedef _list_iterator<T, Ref ,Ptr> self;
	Node* _node;
	_list_iterator(Node* node)
		:_node(node)
	{}

	Ref operator*()
	{
		return _node->_val;
	}

	Ptr operator->()
	{
		return &_node->_val;
	}

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

	self operator++(int)
	{
		_list_iterator temp(*this);
		_node = _node->_next;
		return temp;
	}

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

	self operator--(int)
	{
		_list_iterator temp(*this);
		_node = _node->_prev;
		return temp;
	}


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

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

};
编译器对->的优化问题 

 

创建一个存储结构体的list对象,结构体对成员变量的访问可以通过 变量名.成员变量  或者 结构体指针->成员变量 来实现。我们在重载*和->的时候可以发现,对it进行*解引用操作找到的是一个结构体,该结构体使用.操作符去访问成员变量,这是合理的;但是对it进行->操作时找到的是一个结构体指针,结构体指针要去访问成员变量,应该再次使用->,it->_a1代码应该是写成(it->)->_a1的,但是编译器对其进行了优化,直接用一个->就可以实现迭代器对结构体成员变量的访问

Ref和Ptr

在实现const_iterator时,不能直接typedef const _list_iterator<T, Ref ,Ptr> const_self,因为const的作用是不能改变迭代器所指向的内容,迭代器本身是可以改变的。所以要实现const_list_iterator 只需要在_list_iterator这个类内部对*和->的返回值进行限制。那么*和->的返回值就不只有T& 和T*,还有const T& 和const T*,将返回值重新定义为新的模板参数Ref和Ptr

3.3list基本功能的实现

	//双向带头循环链表
	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef _list_iterator<T,T&,T*> iterator;
		typedef _list_iterator<T,const T&,const T*> const_iterator;

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

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

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

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

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}

		list()
		{
			empty_init();
		}

		//拷贝构造
		list(const list<T>& lt)
		{
			empty_init();
			for (auto& e : lt)
			{
				push_back(e);
			}

		}

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

		}

		//赋值运算符重载
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

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

			_size = 0;
		}

		void push_back(const T& x = T())
		{
			/*Node* newnode = new Node(x);
			Node* tail = _head->_prev;
			tail->_next = newnode;
			newnode->_prev = tail;

			newnode->_next = _head;
			_head->_prev = newnode;*/

			insert(end(), x);
		}

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

		void pop_back()
		{
			erase(--end());
		}

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

		//在pos位置之前插入数据
		iterator insert(iterator pos, const T& x=T())
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);

			newnode->_next = cur;
			cur->_prev = newnode;
			prev->_next = newnode;
			newnode->_prev = prev;
			_size++;

			return newnode;

		}

		//删除pos位置的数据
		iterator erase(iterator pos)
		{
			assert(pos != end());

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

			prev->_next = next;
			next->_prev = prev;
			delete cur;
			_size--;

			return next;
		}

		size_t size()
		{
			return _size;
		}
	private:
		Node* _head;
		size_t _size;
		
	};
}

四、vector和list的比较

4.1vector

vector的底层是一块连续的空间,支持用[下标]随机访问元素,时间复杂度为O(1);插入和删除的时候需要搬移元素(插入有时候还需要扩容),时间复杂度为O(N);对空间的利用率高,不容易造成内存碎片,缓存利用率高;迭代器使用原生指针,插入和删除都会导致迭代器的失效问题;适用于需要高效存储,支持随机访问,不关心插入和删除的场景

4.2list

list的底层是一段不连续的空间,不支持[下标]随机访问,访问元素需要遍历,时间复杂度为O(N);插入和删除的时候直接对该位置进行操作,不需要搬移元素,时间复杂度为O(1);对空间的利用率低,容易造成内存碎片,缓存利用率低;迭代器是对原生指针(节点指针)的封装,插入时不存在迭代器失效问题,但删除时会导致迭代器的失效;适用于需要大量的插入和删除,但不关心随机访问的场景

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

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

相关文章

JavaScript做网页是否过期的处理

通过路由上的参数生成唯一md5和路由上token做验证_md5 token-CSDN博客 前言&#xff1a;基于这篇文章我们做网页是否超时&#xff0c;网页是否过期的处理。打开一个网页允许他在一定时间内可以访问&#xff0c;过了这个时间就不可以访问了&#xff0c;encrypt是h5加密方法&…

数据仓库基础理论—维度建模(图文详解)

数据仓库基础理论—维度建模 维度建模是数据仓库设计中的一种核心方法&#xff0c;旨在以业务角度组织数据&#xff0c;使其更易于理解、查询和分析。 1. 维度模型的基本概念 1.1 事实表&#xff08;Fact Table&#xff09;&#xff1a; 事实表是维度模型的核心&#xff0…

ARM编程指令二

一、算术指令 1. add指令 功能: 将两个操作数相加&#xff0c;并将结果存储在目标寄存器中。 ADD R0, R1, R2 // R0 R1 R22. sub指令 功能: 将第二个操作数从第一个操作数中减去&#xff0c;并将结果存储在目标寄存器中。 SUB R0, R1, R2 // R0 R1 - R23.ADC指令- 带…

强化学习机械臂

一.前言 这里记录一下我学习强化学习的一些知识&#xff0c;并希望在今后可以通过仿真成功验证算法&#xff0c;如果时间允许的情况下希望可以结合到真实机械臂上。 二.学习过程 机械臂强化学习实战&#xff08;stable baselines3panda-gym&#xff09; 这里我先用anaconda创…

【原创教程】电气电工常用剥线钳和压线钳(入门篇)

今天我们来看一下电气电工经常会用到的工具&#xff0c;剥线钳和压线钳。 首先我们看剥线钳做什么用&#xff1f;主要就是剥线&#xff0c;让内部的铜丝裸露。我们来看一下&#xff0c;我们经常用到的剥线钳。 1、带刃口剥线钳 2、自动剥线钳 3、鸭嘴剥线钳 下面看压嘴剥线钳…

Nodejs的使用

1.安装nodejs服务器。 java 项目可以运行在 tomcat 服务器&#xff0c;开始完成前后端完全分离。前端有自己独立的工程。我们需 要把前端独立的工程运行起来。 --- 运行在 nodejs 服务器下。 理解为 tomcat 服务器 安装成功后在命令窗口查看 1.1 安装npm java 项目需要依赖…

finalshell连接kali-Linux失败问题略谈

如果你正在使用fianlshell或者xshell等终端软件远程连接Linux进行工作&#xff0c;但是突然有一天&#xff0c;你死活连不上了&#xff0c;报错提示如下&#xff1a; java.net.ConnectException: Connection refused: connect 就像这样&#xff1a; 哪怕是重装虚拟机&#xff0…

HardSignin _ 入土为安的第十二天

有壳 55 50 58 用010 把vmp改成upx ctrlf2,查找main函数 点第三个 Ctrlx交叉引用 把花指令改了90 一共三处 找db按c 找函数按p封装&#xff0c;按f5反编译函数 smc 用pythonida绕一下 from ida_bytes import * addr 0x00401890 for i in range(170):patch_byte(addr i,…

排序算法----冒泡,插入,希尔,选择排序

冒泡排序 原理 冒泡排序实际上是交换排序&#xff0c;将大的数据通过交换的方式排到一边&#xff0c;依次进行 代码实现 void Swap(int* p1, int* p2) {int temp *p1;*p1 *p2;*p2 temp; }void BullerSort(int* a, int n) {for (int end n - 1; end > 0; end--){for …

卷积神经网络理论(CNN)·基于tensorflow实现

传统神经网络的输入是一维的数据(比如28*28的图片&#xff0c;需要转化为一维向量)。 而卷积神经网络的输入是一个三维的(比如RGB)。 结构 卷积神经网络有以下结构&#xff1a; 输入层卷积层池化层全连接层 输入层 顾名思义&#xff0c;输入层就是输入数据(可以是图片等数…

仅缺一位作者,年内书号

《工程测量学概论》缺第三 《风景园林设计与施工技术研究》缺第二 《对外汉语教学方法与实践研究》缺第三 《基于视觉传达设计下的民间艺术发展研究》缺第三 《英语教学基础与翻译技巧》缺第三 《博物馆学体系与博物馆探究学习》缺第三 《新时期高校辅导员工作与队伍建设研究》…

迈向数智金融:机器学习金融科技新纪元的新风采

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

怎么通过 ssh 访问远程设备

文章目录 什么是 SSH背景环境配置前置准备在 linux 系统中安装 ssh 组件 什么是 SSH ssh 全称是 Secure Shell, 有时候也被叫做 Secure Socket Shell, 这个协议使你能通过命令行的方式安全的连接到远端计算机。当连接建立就会启动一个 shell 会话&#xff0c;这时你就能在你的…

Kubernetes中间件监控指标解读

监控易是一款功能强大的IT监控软件&#xff0c;能够实时监控和分析各种IT资源和应用的状态&#xff0c;为企业提供全面而深入的监控服务。在Kubernetes中间件监控方面&#xff0c;监控易提供了详尽的监控指标&#xff0c;帮助用户全面了解Kubernetes集群的运行状态和性能表现。…

一键PDF翻译成中文,划重点轻松get

现在信息多得跟海一样&#xff0c;PDF文件里全是宝贵的资料和文章。但是&#xff0c;看着满屏幕的外国字&#xff0c;你是不是也头疼过&#xff1f;别发愁&#xff0c;今天咱们就来好好聊聊pdf翻译成中文的工具&#xff0c;帮你轻松搞定语言障碍&#xff0c;一点按钮&#xff0…

电测量数据交换DLMS∕COSEM组件第61部分:对象标识系统(OBIS)(上)

1.范围 GB/T 17215.6的本部分规定了对象标识系统(OBIS)的总体结构并将测量设备中的所有常用数据项映射到其标识代码。 OBIS为测量设备中的所有数据都提供唯一的标识符,不仅包括测量值,而且还包括仪表设备的配置或获取测量设备运行状态的抽象数据。本部分定义的ID代码用作标…

论文解析——CRNN算法

论文paper地址&#xff1a;An End-to-End Trainable Neural Network for Image-based Sequence Recognition and Its Application to Scene Text Recognition 本文的主要目的是识别图片中的序列文字的识别。CRNN的主要贡献在于提出了一个网络架构&#xff0c;这种架构具有以下…

基于飞腾平台的Kafka移植与安装

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

java基础 之 集合与栈的使用(一)

文章目录 集合特点&#xff08;从整体性来看&#xff09;区别List接口&#xff08;一&#xff09;实现类&#xff1a;ArrayList&#xff08;二&#xff09;实现类&#xff1a;LinkedList 集合 java集合可分为Set、List、Queue和Map四种体系。其中List、Set、Queue均继承自Coll…

ADC静态误差

0 前言 图1 表示测量数据精密度高&#xff0c;但准确度较差&#xff1b;图2 表示测量数据的准确度高&#xff0c;但精密度差&#xff1b;图3 表示测量数据精密度和准确度都好&#xff0c;即精确度高。 1 简介 模数转换器&#xff08;ADC&#xff09;广泛用于各种应用中&…