C++修炼之路之list模拟实现--C++中的双向循环链表

news2024/11/15 6:50:29

目录

引言 

一:STL源代码中关于list的成员变量的介绍

二:模拟实现list

1.基本结构

2.普通迭代器 +const迭代器的结合

3.构造+拷贝构造+析构+赋值重载 +清空

4.insert+erase+头尾插入删除 

 5.打印不同数据类型的数据《使用模板加容器来完成》

三:全部代码加测试用例链接 

接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧

引言 

在前面的数据结构中已经实现了c版本的list-双向循环链表,但在c++中注重的是分装,对于操作进行封装处理,对于我们使用便是方便了不少,但模拟实现的话还是有许多要注意的细节点,尤其是list的迭代器较复杂,需要认真理解

一:STL源代码中关于list的成员变量的介绍

在源代码中使用一个头结点的指针来 模拟实现的,但在文档中只介绍list是一个双向链表的容器,并没有说明是否带哨兵位了,之时就得观察初始化函数和构造函数等来观察

 所以从这里就可以看出list的结构就是一个带头循环双向链表,接下来我们就开始模拟实现

二:模拟实现list

1.基本结构

template<class T>//泛型编程
struct list_node
{
	T _data;
	list_node<T>* _prev;
	list_node<T>* _next;

	list_node(const T &x=T())//缺省值为匿名对象
		:_data(x)
		,_prev(nullptr)
		,_next(nullptr)
	{}
};

template<class T>
class list
{
	typedef list_node<T> node;
public:

private:
	node* head;
	size_t size;//方便size()接口,省去便利的开销
};

2.普通迭代器 +const迭代器的结合

对于用迭代器来遍历list的数据,就不能像vector和string那样,直接使用,因为

list<int>::iterator it=lt1.begin();

while(it!=lt1.end())

{

     cout<<*it<<" ";

     ++it;

}

cout<<endl;

对于这里面的*it和++it和it!=lt1.end()这些操作是不能直接支持的,因为*it是要取data的数据,++it就是要使_node=_node->next等,这些是和vector,string是不一样的,所以得自己手动支持,运用运算符重载+函数封装,我们先来观察源代码中的实现

我们先来实现普通迭代器

 

template<class T>
struct _list_iterator
{
	typedef list_node<T> Node;
	typedef _list_iterator<T> self;
	Node* node;

	_list_iterator(Node*node)
		:_node(node)
	{}

	self& operator++()
	{
		_node = _node->next;
		return *this;
	}
	self& operator--()
	{
		_node = _node->prev;
		return *this;
	}
	self operator++(int)
	{
		self tmp(*this);
		_node = _node->next;
		return tmp;
	}
	self operator--(int)
	{
		self tmp(*this);
		_node = _node->prev;
		return tmp;
	}
	T& operator*()
	{
		return _node->data;
	}
	T* operator->()
	{
		return &_node->data;
	}
	bool operator!=(const self& s)
	{
		return _node != s._node;
	}
	bool operator==(const self& s)
	{
		return _node == s._node;
	}

};
template<class T>
class list
{
	typedef list_node<T> node;
public:
	typedef _list_iterator<T> iterator;
	iterator begin()
	{
		//return iterator(_head->_next);
		return _head->_next;
	}
	iterator end()
	{
		return _head;
	}

对于这个结构可以这样来理解

 

 我们知道const对象使用的是const迭代器那么在iterator之前加const的话,这样const iterator指的是迭代器本身不能修改,但在遍历过程迭代器本身是要改变的,如++it等,所以不能这样写

应该为const_iterator这是一个重新定义的一个类型,要做到迭代器本身可以改变,但迭代器指向的内容不能改变

在原来普通迭代器的基础上重载出一份const迭代器的版本如

但这样的话对于普通迭代器和const迭代器两份代码是由许多相同的代码的,比较冗余,所以在源代码中提出了一份更好的解决方案来解决这个问题 

在原来基础上多添加两个参数,这样对于同一个类模板,实例化参数不同就是不同的类型

对于上面的代码就要优化为更完善的代码,展示主要优化的代码

 

template<class T,class Ref,class Ptr>
struct _list_iterator
{
	typedef list_node<T> Node;
	typedef _list_iterator<T,Ref,Ptr> self;
	Node* node;
	
	Ref operator*()
	{
		return _node->data;
	}
	Ptr operator->()
	{
		return &_node->data;
	}
	
	typedef _list_iterator<T,T&,T*> iterator;
	typedef _list_iterator<T, const T&, const T*> const_iterator;
	//typedef __list_const_iterator<T> const_iterator;
	iterator begin()
	{
		//return iterator(_head->_next);
		return _head->_next;
	}
	iterator end()
	{
		return _head;
	}
	const_iterator begin()const
	{
		//return iterator(_head->_next);
		return const_iterator(_head->_next);
	}
	const_iterator end()const
	{
		return const_iterator(_head);
	}

对于->编译器是做处理的,将两个->优化为一个详细看代码及测试 用例3中

3.构造+拷贝构造+析构+赋值重载 +清空

构造时要使用带头循环双向循环链表的初始化操作,观看https://blog.csdn.net/Miwll/article/details/136593441?spm=1001.2014.3001.5502

 

void empty_init()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
	_size = 0;
}
list()
{
	empty_init();
}
list(const list<T>& t)//拷贝构造实现为深拷贝
{
	empty_init();
	for (auto e : t)
	{
		push_back(e);
	}
}
/*list<int>& operator=(const list<int>& lt)
{
	if (this != &lt)
	{
		clear();
		for (auto e : lt)
		{
			push_back(e);
		}
	}
	return *this;
}*/
void swap(list<T>& t)
{
	std::swap(_head,t._head);
	std::swap(_size, t._size);
}
list<int>& operator=(const list<int>& lt)
{
	swap(lt);
	return *this;
}
~list()
{
	clear();
	delete _head;
	_head =nullptr;
}
void clear()
{
	iterator it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}

4.insert+erase+头尾插入删除 

void push_back(const T& x)
{
	insert(end(), x);
}

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

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

void pop_back()
{
	erase(--end());
}
iterator insert(iterator pos, const T& x)
{
	Node* cur = pos._node;
	Node* newnode = new Node(x);
	Node* prev = cur->_prev;

	prev->_next = newnode;
	newnode->_prev = prev;
	newnode->_next = cur;
	cur->_prev = newnode;
	++_size;
	return iterator(newnode);
}
iterator erase(iterator pos)
{
	Node* cur = pos._node;
	Node* next = cur->_next;
	Node* prev = cur->_prev;

	delete cur;
	prev->_next = next;
	next->_prev = prev;
	--_size;
	return iterator(next);
}
size_t size()
{
	return _size;
}

 5.打印不同数据类型的数据《使用模板加容器来完成》

使用模板来打印自定义类型数据,注意这里加的typename

list<T>未实例化的类模板,编译器不能去他里面去找
编译器就无法list<T>::const_iterator是内嵌类型,还是静态成员变量
前面加一个typename就是告诉编译器,这里是一个类型,等list<T>实例化
再去类里面去取

三:全部代码加测试用例链接 

https://gitee.com/lin-ciyu/cplusplus/tree/master/my_list/my_list

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

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

相关文章

水库之大坝安全监测系统解决方案

一、系统介绍 水库之大坝安全监测系统主要包括渗流监测系统、流量监测系统、雨量监测系统、沉降监测系统组成。每一个监测系统由监测仪器及自动化数据采集装置&#xff08;内置通信装置、防雷设备&#xff09;、附件&#xff08;电缆、通信线路、电源线路&#xff09;等组成&a…

YOLO算法改进Backbone系列之:HAT-Net

本文旨在解决ViT中与多头自我关注&#xff08;MHSA&#xff09;相关的高计算/空间复杂性问题。为此&#xff0c;我们提出了分层多头自注意&#xff08;H-MHSA&#xff09;&#xff0c;这是一种以分层方式计算自注意的新方法。具体来说&#xff0c;我们首先按照通常的方法将输入…

llama-factory SFT系列教程 (二),大模型在自定义数据集 lora 训练与部署

文章目录 简介支持的模型列表2. 添加自定义数据集3. lora 微调4. 大模型 lora 权重&#xff0c;部署问题 参考资料 简介 文章列表&#xff1a; llama-factory SFT系列教程 (一)&#xff0c;大模型 API 部署与使用llama-factory SFT系列教程 (二)&#xff0c;大模型在自定义数…

ClickHouse--18--argMin() 和argMax()函数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 argMin() 和argMax()函数业务场景使用案例1.准备表和数据&#xff1a;业务场景一&#xff1a;查看salary 最高和最小的user业务场景二&#xff1a;根据更新时间获取…

一种基于OpenCV的图片倾斜矫正方法

需求描述&#xff1a; 对倾斜的图片进行矫正&#xff0c;返回倾斜角度和矫正后的图片。 解决方法&#xff1a; 1、各种角度点被投影到一个累加器阵列中&#xff0c;其中倾斜角度可以定义为在最大化对齐的搜索间隔内的投影角度。 2、以不同的角度旋转图像&#xff0c;并为每…

Chatgpt掘金之旅—有爱AI商业实战篇|编写代码业务|(十九)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、程序员使用 ChatGPT 进行编码搞副业 程序员不仅拥有将抽象概念转化为实际应用的能力&#xff0c;还通常具备强大的逻辑思维和问题解决能力。然而&#xff0c;许多程序员并…

宝塔面板安装软件 提示需要[xxxMB]内存 强制不能安装

解决方法&#xff1a; 第一步&#xff1a; 编辑修改/www/server/panel/class/下的文件panelPlugin.py vi /www/server/panel/class/panelPlugin.py注释以下判断的内容&#xff1a; ## 第二步&#xff1a; 重启宝塔面板&#xff0c;然后安装即可 bash bt 1

ROS 2边学边练(25)-- 将多个节点组合到一个进程

前言 在ROS 2中&#xff0c;将多个节点&#xff08;Nodes&#xff09;组合到一个单独的进程&#xff08;Process&#xff09;中通常指的是使用“Composable Nodes”的特性。这个特性允许你定义可复用的组件&#xff08;Components&#xff09;&#xff0c;然后将这些组件加…

如何在MobaXterm上使用rz命令

1、首先输入命令和想下载的文件&#xff0c;如下图&#xff1a; 2、按住ctrl鼠标右键&#xff0c;选择如下选项&#xff1a; 上传命令是rz&#xff0c;选择Receive...... 下载命令是sz&#xff0c;选择Send...... 3、我这里是要把Linux上的文件下载到我的本地window磁盘&…

Django之rest_framework(三)

一、GenericAPIView的使用 rest_framework.generics.GenericAPIView 继承自APIVIew,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类 1.1、属性 serializer_class 指明视图使用的序列化器…

记录一下买了腾讯云服务器后如何第一次连MobaXterm

首先是你要用SwitchHost把hosts的映射地址改成你新买的服务器的&#xff08;如果你没这个软件&#xff0c;可以直接在etc/hosts里改 &#xff09; 再连MobaXterm 然后&#xff0c;关键的来了 成功&#xff01;

2024/4/15 网络编程day3

一、TCP机械臂测试 通过w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 注意&#xff1a;关闭计算机的杀毒软件&#xff0c;电脑管家&#xff0c;防火墙 1&#…

openGauss学习笔记-261 openGauss性能调优-使用Plan Hint进行调优-将部分Error降级为Warning的Hint

文章目录 openGauss学习笔记-261 openGauss性能调优-使用Plan Hint进行调优-将部分Error降级为Warning的Hint261.1 功能描述261.2 语法格式261.3 示例261.3.1 忽略非空约束261.3.2 忽略唯一约束261.3.3 忽略分区表无法匹配到合法分区261.3.4 更新/插入值向目标列类型转换失败 o…

3.MMD快捷键操作及人物绑定配饰

快捷键 1. 模型界面切换 按一下TAB键&#xff0c;就从人物模型切换到照明模型 再按一下TAB键&#xff0c;就能从照明模型切换回人物模型 2. 选中全部模型 当模型界面是人物模型时 而且电脑输入法时英文时 按一下A键&#xff0c;可以把人物骨骼全部选中&#xff0c;方便旋转…

互联网轻量级框架整合之MyBatis配置详解

MyBatis核心配置文件mybatis-config.xml里有诸多配置项&#xff0c;但常用的就无非就如下这么多 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTDConfig3.0//EN" "https://mybati…

【爬虫开发】爬虫从0到1全知识md笔记第5篇:Selenium课程概要,selenium的其它使用方法【附代码文档】

爬虫开发从0到1全知识教程完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;爬虫课程概要&#xff0c;爬虫基础爬虫概述,,http协议复习。requests模块&#xff0c;requests模块1. requests模块介绍,2. response响应对象,3. requests模块发送请求,4. request…

“成像光谱遥感技术中的AI革命:ChatGPT在遥感领域中的应用“

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用&#xff0c;人工智能…

[lesson31]完善的复数类

完善的复数类 完善的复数类 复数类应该具有的操作 运算&#xff1a;&#xff0c;-&#xff0c;*&#xff0c;/比较&#xff1a;&#xff0c;!赋值&#xff1a;求模&#xff1a;modulus 利用操作符重载 统一复数与实数的运算方式统一复数与实数的比较方式 注意事项 C规定赋…

CLI举例:上行连接路由器(业务引流),下行连接交换机(VRRP引流)

CLI举例&#xff1a;上行连接路由器&#xff08;业务引流&#xff09;&#xff0c;下行连接交换机&#xff08;VRRP引流&#xff09; 介绍了设备上行连接路由器&#xff0c;下行连接交换机的集群配置举例。 组网需求 如图1所示&#xff0c;FW与路由器之间运行OSPF协议。 希望…

21、矩阵-搜索二维矩阵

思路&#xff1a; 这道题很有意思 从左到有升序&#xff0c;从上到下升序&#xff0c;斜边从左上到右下也是升序&#xff0c;从右上到做下降序。 如果是从左往右依次遍历&#xff0c;就会面临一个问题向右还是向下&#xff0c;因为都是大于当前值&#xff0c;不好决断&#x…