STL——list模拟实现

news2025/1/13 14:20:43

一、模拟实现源码

#pragma once

namespace sjx
{
	template <typename T>
	struct __list_node
	{
		__list_node<T>* _next;
		__list_node<T>* _prev;
		T _data;

		__list_node(const T& val = T()) :_data(val), _next(nullptr), _prev(nullptr)
		{

		}
	};

	template <typename T, typename Ref, typename Ptr>
	struct __list_iterator
	{
		typedef __list_node<T> node;
		typedef __list_node<T>* node_pointer;

		typedef __list_iterator<T, Ref, Ptr> self;
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		node_pointer _pnode;

		__list_iterator(const node_pointer& val = nullptr) :_pnode(val) {}
		__list_iterator(const iterator& it) :_pnode(it._pnode) {}

		Ref operator*()
		{
			return _pnode->_data;
		}
		Ptr operator->()
		{
			return &(_pnode->_data);
		}
		bool operator!=(const self& val) const
		{
			return _pnode != val._pnode;
		}
		bool operator==(const self& val) const
		{
			return _pnode == val._pnode;
		}

		self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}
		self operator++(int)
		{
			self tmp(_pnode);
			_pnode = _pnode->_next;
			return tmp;
		}
		self& operator--()
		{
			_pnode = _pnode->_prev;
			return *this;
		}
		self operator--(int)
		{
			self tmp(_pnode);
			_pnode = _pnode->_prev;
			return tmp;
		}
	};

	template <typename T>
	class list
	{
	public:
		typedef __list_node<T> node;
		typedef __list_node<T>* node_pointer;

		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		list()
		{
			empty_initialize();
		}
		template <typename InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_initialize();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		list(const list& other)
		{
			empty_initialize();
			list<T> tmp(other.begin(), other.end());
			swap(tmp);
		}

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

		list<T>& operator=(list<T> other)
		{
			empty_initialize();
			swap(other);
			return *this;
		}


		// Element access
		T& front()
		{
			assert(!empty());
			return _head->_next->_data;
		}
		const T& front() const
		{
			assert(!empty());
			return _head->_next->_data;
		}

		T& back()
		{
			assert(!empty());
			return _head->_prev->_data;
		}
		const T& back() const
		{
			assert(!empty());
			return _head->_prev->_data;
		}


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

		
		// Capacity
		bool empty() const
		{
			return _head->_next == _head;
		}
		
		size_t size() const
		{
			size_t i = 0;
			node_pointer cur = _head->_next;
			while (cur != _head)
			{
				++i;
				cur = cur->_next;
			}
			return i;
		}


		// Modifiers
		void clear()
		{
			node_pointer cur = _head->_next;
			while (cur != _head)
			{
				node_pointer tmp = cur->_next;
				delete cur;
				cur = tmp;
			}
			_head->_next = _head;
			_head->_prev = _head;
		}

		iterator insert(const_iterator pos, const T& val)
		{
			node_pointer cur = new node(val);
			node_pointer tail = pos._pnode;
			node_pointer head = tail->_prev;

			head->_next = cur;
			cur->_next = tail;

			tail->_prev = cur;
			cur->_prev = head;

			return cur;
		}
		iterator insert(const_iterator pos, size_t count, const T& val)
		{
			for (size_t i = 0; i < count; ++i)
			{
				pos = insert(pos, val);
			}
			return pos._pnode;
		}
		template <typename InputIterator>
		iterator insert(const_iterator pos, InputIterator first, InputIterator last)
		{
			node_pointer head = pos._pnode;
			if (first != last)
			{
				head = insert(pos, *first)._pnode;
				++first;
			}
			while (first != last)
			{
				insert(pos, *first);
				++first;
			}
			return head;
		}

		iterator erase(const_iterator pos)
		{
			node_pointer tmp = pos._pnode;
			if (pos != end())
			{
				node_pointer del = tmp;
				tmp = tmp->_next;
				del->_prev->_next = del->_next;
				del->_next->_prev = del->_prev;
				delete del;
			}
			return tmp;
		}
		iterator erase(const_iterator first, const_iterator last)
		{
			while (first != last)
			{
				first = erase(first);
			}
			return last._pnode;
		}

		void push_back(const T& val)
		{
			node_pointer tmp = new node(val);
			node_pointer tail = _head->_prev;
			
			tail->_next = tmp;
			tmp->_next = _head;

			_head->_prev = tmp;
			tmp->_prev = tail;
		}

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

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

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

		void swap(list<T>& val)
		{
			std::swap(_head, val._head);
		}
	
	protected:
		void empty_initialize()
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}

	private:
		node_pointer _head;
	};
}

二、重难点——迭代器实现

list的迭代器不同于vector,vector的迭代器用指针就可以实现大部分功能,但是list的迭代器要实现++,不再是单纯数值上的加减,而是要让迭代器指向当前结点的next。

因此,需要将list的迭代器封装成一个类__list_iterator。通过运算符重载,来改变迭代器运算的效果。

需要注意的是__list_iterator还有另外两个模板参数,Ref和Ptr。

对于const_iterator,它与普通的iterator的区别就是它里面的内容不允许被修改,但是本身依旧可以进行++或者--等操作,其区别之一就在于对迭代器的解引用,一个的返回值可以被修改,一个不可以,因此我们引入了一个模板参数Ref,对于普通的迭代器,它被设置为T&,而对于const迭代器,它被设置为const T&。

对于模板参数Ptr,需要应对以下情况:

#include <iostream>
#include <assert.h>
#include "my_list.h"
struct Data
{
	int _year;
	int _month;
	int _day;

	Data(int year = 2000, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{

	}
};

int main()
{
	// 如果存储的对象是自定义类型,且要访问其中的数据
	sjx::list<Data> l1;
	l1.push_back(Data());

	sjx::list<Data>::iterator it = l1.begin();

	// 使用 * 访问
	std::cout << (*it)._year << " " << (*it)._month << " " << (*it)._day << std::endl;
	// 使用 operator->
	std::cout << it.operator->()->_year << " " << it.operator->()->_month << " " << it.operator->()->_day << std::endl;
	// 为了可读性,一般我们省略了一个 ->
	std::cout << it->_year << " " << it->_month << " " << it->_day << std::endl;

	return 0;
}

以上三种输出方式实际上是等价的。

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

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

相关文章

HandlerMethodArgumentResolver :深入spring mvc参数解析机制

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; 搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到三十…

【Pyhton】读取寄存器数据到MySQL数据库

目录 步骤 modsim32软件配置 Navicat for MySQL 代码实现 步骤 安装必要的库&#xff1a;确保安装了pymodbus和pymysql。 配置Modbus连接&#xff1a;设置Modbus从站的IP地址、端口&#xff08;对于TCP&#xff09;或串行通信参数&#xff08;对于RTU&#xff09;。 连接M…

昇思25天学习打卡营第10天 | 自然语言处理:RNN实现情感分类

1. RNN实现情感分类 1.2 概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative(负面) 预测标签: Negative输…

AlphaGo 背后的人工智能:机器学习和神经网络

文章目录 一、说明二、背景三、围棋游戏四、AlphaGo 算法五、神经网络六、AlphaGo 的未来七、人工智能的未来八、结论 一、说明 棋盘游戏围棋被视为人工智能最具挑战性的任务之一&#xff0c;因为它“复杂、基于模式且难以编程”。计算机程序 AlphaGo 战胜李世石成为人工智能和…

秋招突击——7/4——复习{}——新作{最长公共子序列、编辑距离}

文章目录 引言复习新作1143-最长公共子序列个人实现 参考实现编辑距离个人实现参考实现 贪心——买股票的最佳时机个人实现参考实现 贪心——55-跳跃游戏个人实现参考做法 总结 引言 昨天主要是面试&#xff0c;然后剩下的时间都是用来对面试中不会的东西进行查漏补缺&#xff…

xxl-job集成SpringBoot

安装xxl-job客户端一般有很多方式&#xff0c;我这里给大家提供两种安装方式&#xff0c;包含里面的各项配置等等。 前期需要准备好MySQL数据库。复制SQL到数据库里面。 # # XXL-JOB v2.4.2-SNAPSHOT # Copyright (c) 2015-present, xuxueli.CREATE database if NOT EXISTS x…

代码动态编译

背景 开发环境下新加代码、改代码时要重启后生效&#xff08;耗时间&#xff09;&#xff1b;需求:不用重启且支持springboot 、spring、MyBatis。 实现 下地地址&#xff1a;https://github.com/JetBrains/JetBrainsRuntime/releases 1.根据系统类型下载压缩包 2.解压后配…

手动将dingtalk-sdk-java jar包打入maven本地仓库

有时候,中央镜像库不一定有自己需要的jar包,这时候我们就需要用到该方法,将jar打入maven本地仓库,然后项目中,正常使用maven的引入规则。 mvn install:install-file -Dmaven.repo.local=D:\software\maven\apache-maven-3.6.3-bin\apache-maven-3.6.3\repo -DgroupId=ding…

生态共建 | 华宇TAS应用中间件与新华三服务器完成兼容互认证

近日&#xff0c;华宇TAS应用中间件完成与新华三技术有限公司的R4930系列和R4970 G7服务器的兼容适配&#xff0c;认证测试报告显示&#xff0c;双方产品兼容性良好&#xff0c;运行稳定、安全&#xff0c;可以满足用户对双方功能的要求。 新华三技术有限公司 新华三技术有限公…

《Winodws API每日一练》8.2 static控件

在 Windows 编程中&#xff0c;"Static" 控件是一种常见的用户界面元素&#xff0c;用于显示静态文本或图像&#xff0c;而无法进行用户交互。它通常用于显示标签、标题、说明文本或静态图像等信息。Static 控件是一种静态的、只读的显示元素&#xff0c;不接受用户的…

ConsiStory:无需训练的一致性文本到图像生成技术

随着大规模文本到图像&#xff08;T2I&#xff09;扩散模型的发展&#xff0c;用户可以更自由地通过文本指导图像生成过程。然而&#xff0c;要在不同的提示中保持同一主题的视觉一致性仍然是一个挑战。现有的方法通常需要对模型进行微调或预训练&#xff0c;以教授新词汇来描述…

信息安全驱动汽车行业快速向数字化转型

开发一款安全性良好的软件是困难的&#xff0c;它需要专业知识的积累以及对常见编程缺陷和规则的了解&#xff0c;例如检查输入范围、管理内存分配和回收、寻址字符串格式、避免悬空指针等等。通常情况下&#xff0c;编写安全代码与开发人员编写“流畅”代码的自然愿望形成了对…

滤波算法学习笔记

目录 引言 一、定义 二、分类 三、常见滤波算法 四、应用与优势 五、发展趋势 例程 1. 均值滤波&#xff08;Moving Average Filter&#xff09; 2. 中值滤波&#xff08;Median Filter&#xff09; 3. 高斯滤波&#xff08;Gaussian Filter&#xff09; 4.指数移动…

新技术 高效的碳捕捉技术设计

网盘 https://pan.baidu.com/s/1mUlEhbQ6LBHYdmfg-du9bw?pwdc7gk 一种用于高效捕集CO_Sub_2__Sub_的生物炭颗粒吸附剂及其制备方法和应用.pdf 基于双相离子溶液的高效碳捕集及节能再生装置.pdf 基于水合物法低温液化的高效碳捕集系统及其操作方法.pdf 碳捕集系统及方法.pdf 高…

Feign远程调用,请求头丢失情况

现象 解决方案 import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolde…

一篇文章说清楚Filter(过滤器)、Interceptor(拦截器)和AOP(切面儿)

文章目录 前言一、Filter&#xff08;过滤器&#xff09;1.说明2.实现filterChain.doFilter() 3.order优先级4.解决跨域5.拦截返回错误信息JSON 二、Interceptor&#xff08;拦截器&#xff09;1.说明2.实现preHandlepostHandleafterCompletion 3.执行顺序图4.排除特定路径拦截…

C#/.NET/.NET Core编程技巧练习集

DotNet Exercises介绍 DotNetGuide专栏C#/.NET/.NET Core编程常用语法、算法、技巧、中间件、类库练习集&#xff0c;配套详细的文章教程讲解&#xff0c;助你快速掌握C#/.NET/.NET Core各种编程常用语法、算法、技巧、中间件、类库等等。 GitHub开源地址&#xff1a;https://…

MedCLIP:CLIP + 医学语义匹配策略,解决模型误将不同患者同病症视为不相关

MedCLIP&#xff1a;CLIP 医学语义匹配策略&#xff0c;解决模型误将不同患者同病症视为不相关 提出背景流程图解法拆解子解法1&#xff1a;知识提取子解法2&#xff1a;视觉和文本编码器子解法3&#xff1a;语义匹配损失 提出背景 论文&#xff1a;https://arxiv.org/pdf/22…

【SkiaSharp绘图15】SKPath属性详解:边界、填充、凹凸、类型判断、坐标、路径类型

文章目录 SKPath 构造函数SKPath 属性Bounds 边界(宽边界)TightBounds紧边界FillType填充方式IsConcave 是否凹/ IsConvex 是否凸IsEmpty是否为空IsLine是否为线段IsRect是否为矩形IsOval是否为椭圆或圆IsRoundRect是否为圆角矩形Item[] 获取路径的坐标LastPoint最后点的坐标Po…

JavaScript——while类型

目录 任务描述 相关知识 while类型 编程要求 任务描述 质数的定义如下&#xff1a;大于1的自然数&#xff0c;且除了1和本身外没有别的因数。如2、3、5、7。 本关任务&#xff1a;利用循环结构求质数的和。 相关知识 在选择结构中&#xff0c;条件会被测试一次&#xff…