当前位置: 首页 > news >正文

C++:模拟实现list

目录

节点

迭代器

整体框架

构造函数

empty_init

拷贝构造

赋值重载

析构函数

clear

insert

erase

push_back和push_front

pop_back和push_front

size

empty


节点

对于链表节点,我们需要一个数据、一个前驱指针、一个后继指针来维护,并且将其封装成一个类。

template<class T>
struct list_node
{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& data = T()):_data(data),_next(nullptr),_prev(nullptr){}
};

使用struct的原因是因为,struct默认的域作用限定符是public,方便后续使用,不用走友元的那一套。

迭代器

我们知道迭代器提供访问容器的方法,之前实现vector和string时,迭代器用的就是数据类型的指针,但是list不可以直接用。因为vector和string的数据在内存的存放都是连续的,如果想找下一个数据的指针(迭代器),直接(迭代器)指针++就可以了;但是list的数据存放在内存不是连续的,如果直接把指针当成迭代器,迭代器++是找不到下一个数据的迭代器

所以综上所述,我们应该用类对链表数据类型的指针封装成迭代器在类里重载操作符让其达到我们想要的效果。

当然,我们实现的迭代器应该有两个版本,普通版本和const版本。

//普通迭代器
template<class T>
struct list_iterator
{typedef list_node<T> Node;typedef list_iterator<T> Self;Node* _node;list_iterator(Node* node):_node(node){}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}//前置++Self& operator++() {_node = _node->_next;return *this;}//后置++Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}//前置--Self& operator--(){_node = _node->_prev;return *this;}//后置--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& it) const{return _node != it._node;}bool operator==(const Self& it) const{return _node == it._node;}
};
​//const迭代器
template<class T>
struct list_const_iterator
{typedef list_node<T> Node;typedef list_const_iterator<T> Self;Node* _node;list_const_iterator(Node* node):_node(node){}const T& operator*(){return _node->_data;}const T* operator->(){return &_node->_data;}Self& operator++() {_node = _node->_next;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(){_node = _node->_prev;return *this;}bool operator!=(const Self& it) const{return _node != it._node;}bool operator==(const Self& it) const{return _node == it._node;}
};​

我们发现这两份代码,除了重载*和->有所不同,其余代码都是一样的,所以我们可以增加两个模板参数,将这两份代码合二为一。

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->_data;}Ptr operator->(){return &_node->_data;}Self& operator++() //前置++{_node = _node->_next;return *this;}Self operator++(int) // {Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& it) const{return _node != it._node;}bool operator==(const Self& it) const{return _node == it._node;}
};

 增加Ref和Ptr模板参数,让T*和T&作为参数传入,这就可以解决将两份代码合二为一。

整体框架

​
​
template<class T>
class list
{typedef list_node<T> Node; 
public:/*typedef list_iterator<T> iterator;typedef list_const_iterator<T> const_iterator;*///将T&和T*作为参数传入typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin(){/*iterator it(_head->_next);return it;*///return iterator(_head->_next);//返回哨兵节点的下一个节点(第一个有效节点)//隐式类型转换return _head->_next;}iterator end(){//最后一个有效节点的下一位置,也就是哨兵节点return _head;}const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}//实现各种函数......private:Node* _head;size_t _size;
};​​

构造函数

empty_init

多种构造函数的代码都有重合,所以把重合部分独立成一个函数。

​
void empty_init()
{//创造哨兵节点_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;
}​

普通构造

普通构造就是创造哨兵节点,调用empty_init即可。

//普通构造
list()
{empty_init();
}

列表构造

C++11的用法,用法例子如下:

list<int> lt1 = { 1,2,3,4,5,6 };

 先创造一个哨兵节点,然后将列表的元素尾插即可

//列表构造
list(initializer_list<T> il)
{empty_init();for (auto& e : il){push_back(e);}
}

关于列表initializer_list<T>的知识,可以看以下连接。

介绍列表

拷贝构造

创建哨兵节点,将链表元素尾插到待构造的链表就完成拷贝构造了。

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

赋值重载

临时对象lt交换即可,跟string、vector的实现类似。

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;
}

析构函数

clear

清理除了哨兵节点以外的所有节点。

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

先将链表clear掉,然后清理哨兵节点。  

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

insert

在pos(迭代器)位置前插入元素x,插入后_size++,返回新插入元素的迭代器。

iterator insert(iterator pos, const T& x)
{Node* cur = pos._node; //pos是iterator类的对象,访问里面的成员变量用pos._node,不能用pos->_nodeNode* prev = cur->_prev;Node* newnode = new Node(x);newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;prev->_next = newnode;++_size;//隐式类型转换return newnode;
}

erase

删除pos位置的元素,删除后_size--,返回删除元素的下一元素的迭代器。

iterator erase(iterator pos)
{assert(pos != end());          //不能删掉哨兵位的节点Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node; --_size;return next;
}

push_back和push_front

利用insert函数就可以实现尾插和头插。

void push_back(const T& x)
{/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;++_size;*/ insert(end(), x);
}void push_front(const T& x)
{insert(begin(), x);
}

pop_back和push_front

利用erase函数实现尾删和头删。

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

size

返回链表有效元素的个数.。

size_t size() const
{return _size;
}

empty

判断链表是否为空。

bool empty() const
{return _size == 0;
}

打印容器的函数。

template<class Container>
void Print_Container(const Container& con)
{//const对象要用const迭代器,这里没实现的话会报错/*auto it = con.begin();while (it != con.end()){cout << *it << " ";++it;}*/for (auto e : con){cout << e << " ";}cout << endl;
}

拜拜,下期再见😏

摸鱼ing😴✨🎞

相关文章:

C++:模拟实现list

目录 节点 迭代器 整体框架 构造函数 empty_init 拷贝构造 赋值重载 析构函数 clear insert erase push_back和push_front pop_back和push_front size empty Print_Container 节点 对于链表节点&#xff0c;我们需要一个数据、一个前驱指针、一个后继指针来维护…...

解锁5 大无水印热门短视频素材库

想让你的抖音视频更出彩吗&#xff1f;想知道那些爆款视频的素材源头吗&#xff1f;快来了解以下 5 个超棒的视频素材下载平台。 蛙学网 国内的视频素材佼佼者&#xff0c;有大量 4K 高清且无水印的素材&#xff0c;自然风光、情感生活等类别任你选&#xff0c;不少还免费&…...

【电商购物管理系统】Python+Django网页界面平台+商品管理+数据库

一、介绍 电商购物管理系统&#xff0c;本系统前端使用HTML、CSS、BootStrap等技术搭建前端界面&#xff0c;后端使用Django框架处理用户的逻辑请求。主要功能有&#xff1a; 管理员登录与管理&#xff1a;管理员可以登录后台&#xff0c;对用户和商品进行增删改查的操作。用…...

AD9248驱动的简易示波器设计——FPGA学习笔记21

一、原理 我们这里设计的是显示 1024 个波形数据点&#xff0c; 在绘制每一行的图像的时候&#xff0c; 比对每一个数据和 VS 的 Y 坐标是否相等&#xff0c; 如果相等就绘制这个波形点。 这样我们就能完成 1024 个波形点在整个屏幕的显示。 二、乒乓操作 可见FPGA实现双口RAM…...

微软十月补丁星期二发现了 118 个漏洞

微软将在2024 年 10 月补丁星期二解决 118 个漏洞&#xff0c;并且有证据表明发布的 5 个漏洞被野蛮利用和/或公开披露&#xff0c;尽管微软尚未将其中任何一个漏洞评定为严重漏洞。 在这五个漏洞中&#xff0c;微软列出了两个已被利用的漏洞&#xff0c;这两个漏洞现在都已列…...

到底是微服务,还是SOA?

引言&#xff1a;大概正式工作有5年了&#xff0c;换了三个大厂【也是真特么世道艰难&#xff0c;中国互联网人才饱和了】。基本上每个公司有的架构都不太相同&#xff0c;干过TOC和TOB的业务&#xff0c;但是大家用的架构都不太相同。有坚持ALL in one的SB&#xff0c;最后服务…...

JDK17常用新特性

目前国内大部分开发人员都是在使用jdk8&#xff0c;甚至是jdk6&#xff0c;但是随着jdk的更新迭代&#xff0c;jdk8我觉得可能就会慢慢的淡出舞台&#xff0c;随着目前主流框架最新版推出明确说明了不再支持jdk8&#xff0c;也促使我不得不抓紧学习了解一波jdk17的新特性&#…...

【分布式微服务云原生】探索负载均衡的艺术:深入理解与实践指南

探索负载均衡的艺术&#xff1a;深入理解与实践指南 摘要&#xff1a; 在本文中&#xff0c;我们将深入探讨负载均衡的概念、重要性以及实现负载均衡的多种算法。通过详细的技术解析、Java代码示例、流程图和对比表格&#xff0c;您将了解如何选择合适的负载均衡策略来优化资源…...

拥抱云原生

专题七&#xff1a;云原生实战72课时 专题简介&#xff1a; 云原生正在改变世界&#xff0c;新一代架构思想ServiceMesh、Serverless改变传统软件架构模式&#xff0c;本专题基于完全云上架构实战&#xff0c;结合微服务架构和云计算平台两者的优势&#xff0c;属于架构师必备…...

关于使用若依并快速构建系统的操作指南

准备阶段--下载源码&#xff08;脚手架&#xff09; 1.1 若依官网地址&#xff1a;https://www.ruoyi.vip/ 1.2 选择“前后端分离版本进行下载”&#xff0c;如下图所示 1.3 跳转gitee后&#xff0c;直接按如下步骤进行下载。 前后端模块分离 解压&#xff0c;并打开到项目…...

【分布式微服务云原生】 选择SOAP还是RESTful API?深入探讨与实践指南

&#x1f310; 选择SOAP还是RESTful API&#xff1f;深入探讨与实践指南 摘要&#xff1a; 在构建现代Web服务时&#xff0c;开发者常常面临一个关键决策&#xff1a;是选择SOAP还是RESTful API&#xff1f;本文将为您提供一个全面的比较&#xff0c;包括两者的适用场景、安全…...

HarmonyOS NEXT 应用开发实战(五、页面的生命周期及使用介绍)

HarmonyOS NEXT是华为推出的最新操作系统&#xff0c;arkUI是其提供的用户界面框架。arkUI的页面生命周期管理对于开发者来说非常重要&#xff0c;因为它涉及到页面的创建、显示、隐藏、销毁等各个阶段。以下是arkUI页面生命周期的介绍及使用举例。 页面的生命周期的作用 页面…...

C# 比较两个集合和比较对象

1、比较集合 /// <summary> /// 比较两个集合 /// </summary> /// <typeparam name"T"></typeparam> /// <param name"list1"></param> /// <param name"list2"></param> /// <returns>&…...

Spark高级用法-自定义函数

用户可以根据需求自己封装计算的逻辑&#xff0c;对字段数据进行计算 内置函数&#xff0c;是spark提供的对字段操作的方法 &#xff0c;split(字段) 对字段中的数进行切割&#xff0c;F.sum(字段) 会将该字段下的数据进行求和 实际业务中又能内置函数不满足计算需求&#xff0…...

『Mysql进阶』Mysql explain详解(五)

目录 Explain 介绍 Explain分析示例 explain中的列 1. id 列 2. select_type 列 3. table 列 4. partitions 列 5. type 列 6. possible_keys 列 7. key 列 8. key_len 列 9. ref 列 10. rows 列 11. filtered 列 12. Extra 列 Explain 介绍 EXPLAIN 语句提供有…...

【工具】音视频翻译工具基于Whisper+ChatGPT

OpenAI推出的开源语音识别工具Whisper&#xff0c;以其卓越的语音识别能力&#xff0c;在音频和视频文件处理领域大放异彩。与此同时&#xff0c;ChatGPT也在翻译领域崭露头角&#xff0c;其强大的翻译能力备受赞誉。因此&#xff0c;一些字幕制作团队敏锐地捕捉到了这两者的结…...

学成在线——关于nacos配置优先级的坑

出错&#xff1a; 本地要起两个微服务&#xff0c;一个是content-api&#xff0c;另一个是gateway网关服务。 发现通过网关服务请求content微服务时&#xff0c;怎么请求都请求不到。 配置如下&#xff1a; content-api-dev.yaml的配置&#xff1a; server:servlet:context-p…...

Nginx在Windows Server下的启动脚本

Nginx在Windows Server下的快捷运行脚本 使用时记得修改NGINX_DIR路径 ECHO OFF CHCP 65001 SET NGINX_DIRD:\software\Nginx\ color 0a TITLE Nginx Management GOTO MENU :MENU CLS ECHO. ECHO. * * * * Nginx Management * * * * * * * * * * * ECHO. * * EC…...

【国科大】C++程序设计秋季——五子棋

【国科大】C程序设计秋季 —— 五子棋程序 下载地址&#xff1a;https://mbd.pub/o/bread/Zp2Ukptx...

Docker 环境下多节点服务器监控实战:从 Prometheus 到 Grafana 的完整部署指南

Docker 环境下多节点服务器监控实战&#xff1a;从 Prometheus 到 Grafana 的完整部署指南 文章目录 Docker 环境下多节点服务器监控实战&#xff1a;从 Prometheus 到 Grafana 的完整部署指南一 多节点部署1 节点一2 节点二3 节点三 二 监控节点部署三 配置 prometheus.yml四 …...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...

从实验室到产业:IndexTTS 在六大核心场景的落地实践

一、内容创作&#xff1a;重构数字内容生产范式 在短视频创作领域&#xff0c;IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色&#xff0c;生成的 “各位吴彦祖们大家好” 语音相似度达 97%&#xff0c;单条视频播放量突破百万…...