Cpp学习——list的模拟实现

目录
一,实现list所需要包含的三个类
二,三个类的实现
1.list_node
2.list类
3.iterator_list类
三,功能实现
1.list类里的push_back()
2.iterator类里的运算符重载
3,list类里面的功能函数
1.insert()
2.erase()函数
3.clear()与析构函数
4.拷贝构造函数赋值运算符重载
5.打印函数
一,实现list所需要包含的三个类
因为list是一个带头双向循环链表。所以list的实现会比较的复杂一些。总得来说,实现一个双向带头循环链表需要构造三个类。1.list类,2.list_node类,3.list_iterator类。前两个类相信大家会比较的熟悉。第三个类大家会比较不熟悉,因为它是一个迭代器的类。也就是说这个类是迭代器的封装。它的实现很有价值,因为它能让我们在使用list时也可以像之前的数据结构一样方便。
二,三个类的实现
1.list_node
这首先要实现的便是节点类。这个类是最容易实现的。这个类的作用便是给要产生的节点画一个图,定义一下这个节点的结构和类型。代码如下:
template<class T>//模板struct list_node{list_node(const T& val =T()//匿名对象 )//构造函数起初始化的作用:val(val), prev(nullptr), next(nullptr){}T val;list_node<T>* prev;list_node<T>* next;};现在你看到了,这个节点的结构便是这样。其实这与之前实现的那个带头双向循环链表的结构差不多。不过,在cpp中引入了模板的概念,所以这个节点便可以调用模板参数来进行泛化。
2.list类
list类的定义可太简单了。list的成员变量只有一个参数,便是_head。这是哨兵位的头节点。当然还有一个无参的构造函数和一个功能函数。代码如下:
template<class T>class list{ public:typedef list_node<T> Node;void empty()//初始化功能函数。{_head = new Node;_head->prev = _head;_head->next = _head;}list()//构造函数{empty();}private:Node* _head;};当然,这里的list类也是要用模板来进行泛化的。
3.iterator_list类
这个类就算是比较复杂的一个类了。因为迭代器要实现两种重载版本:1.普通版本。2.const版本。所以迭代器类的模板参数会有三个:
template <class T, class Ref, class ptr>这三个模板参数会重载两种版本的三个参数:T对象,T&,T指针类型。在这个类里面也只有一个成员:_node。类型与list类里面的成员类型相同。该类代码如下:
template <class T, class Ref, class ptr>struct iterator_list{typedef list_node<T> Node;iterator_list(Node* node):_node(node){}Node* _node;};
三,功能实现
1.list类里的push_back()
首先来实现一个push_back()函数,这个函数的作用便是实现尾插数据。逻辑十分简单,代码如下:
void push_back(const T& val){Node* newnode = new Node(val);Node* tail = _head->prev;tail->next = newnode;newnode->prev = tail;newnode->next = _head;_head->prev = newnode;}写完这个以后,我便想要通过显示list里的数据来验证答案,但是很显然,我们做不到。因为list是一个自定义的类。但是我们有办法,所以我们便可以通过iterator来达到这个目的。所以我们必须在iterator类里面实现几个运算符重载。
2.iterator类里的运算符重载
首先先实先这三个运算符重载:1.*,2.++,3.!=
代码如下:
Ref operator *()//Ref代表T&{return _node->val;}self operator++(){_node = _node->next;return *this;}bool operator!=(self& it){return _node != it._node;}然后再在list类里面实现begin()与end()函数之后便可以实现范围for的使用了,end与begin代码如下:
//实现两个版本的begin与enditerator begin(){return _head->next;}iterator end(){return _head;}const_iterator begin()const{return _head->next;}const_iterator end()const{return _head;}在实现了上面的代码以后,为了让迭代器的功能更加全面,那我们再实现几个函数重载。再iterator_list里面的全部运算符重载如下:
Ref operator *(){return _node->val;}self& operator++()//前置++{_node = _node->next;return *this;}self operator++(int)//后置++{Node* tmp(*this);_node = _node->next;return tmp;}self& operator --()//前置--{_node = _node->prev;return *this;}self operator--(int)//后置--{Node* tmp(*this);_node = _node->prev;return tmp;}bool operator!=(const self& it)//若用引用便要加上const{return _node != it._node;}bool operator==(self& it){return _node == it._node;}self& operator+(int n){while (n){_node = _node->next;n--;}return *this;}ptr operator->()//箭头解引用{return &_node->val;}在实现了这些运算符重载以后,list类里面的功能函数便好写了许多。
3,list类里面的功能函数
1.insert()
这个函数实现的功能便是在pos位置之前插入一个新的节点。这个pos的类型是迭代器类型。在list类里边的迭代器重定义为:
typedef iterator_list<T, T& ,T*> iterator; typedef iterator_list<T, const T&, const T*> const_iterator;我们只需要关注第一个迭代器即可,因为第二个迭代器修饰的对象是不可以修改的。所以insert的实现代码如下:
iterator insert(iterator pos, const T& x)//在pos位置之前插入新节点{Node* newnode = new Node(x);Node* prev = pos._node->prev;prev->next = newnode;newnode->prev = prev;newnode->next = pos._node;pos._node->prev = newnode;return pos._node->prev;//防止迭代器失效,所以返回pos的前一个位置}检验一下,检验代码如下:
void test_list2(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.push_back(5);for (auto e : l1){cout << e << " ";}cout << endl;l1.insert(l1.begin(), 9);l1.insert(l1.end(), 99);for (auto e : l1){cout << e << " ";}cout << endl;}结果:正确
在实现了insert()函数以后便可以复用实现push_back()与push_front()。代码如下:
void push_back(const T& val){insert(begin(), val);}void push_front(const T& val){insert(end(), val);}
2.erase()函数
erase()函数实现的功能便是传入一个位置,然后将该位置上的节点删除掉。代码实现如下:
iterator erase(iterator pos){Node* prev = pos._node->prev;Node* next = pos._node->next;Node* cur = pos._node;delete cur;prev->next = next;next->prev = prev;return iterator(next);//返回新的迭代器}复用erase实现尾删与头删,代码如下:
void pop_back(){erase(--end());//尾巴是--end()的位置}void pop_front(){erase(begin());}实验代码:
void test_list3(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.push_back(5);for (auto e : l1){cout << e << " ";}cout << endl;l1.insert(l1.begin(), 9);l1.insert(l1.end(), 99);for (auto e : l1){cout << e << " ";}cout << endl;l1.pop_back();l1.pop_front();for (auto e : l1){cout << e << " ";}cout << endl;}结果:正确
3.clear()与析构函数
实现了erase()函数以后再接再厉,接着复用实现clear函数,代码如下:
void clear(){iterator it = begin();while (it != end()){it = erase(it);//erase()每次都会返回下一个位置}}从上面代码的逻辑便可以看出clear()函数是不会删除掉头节点的。但是析构函数需要。于是复用clear()函数后析构函数代码如下:
~list(){clear();delete _head;}
4.拷贝构造函数赋值运算符重载
拷贝构造函数实现过程大概分三步,首先new出来一个空间。然后再复用push_back()函数将要赋值的数据拷贝到新节点内。实现代码如下:
list(const list<T>& l1){empty();for (auto e : l1){push_back(e);}}实现了拷贝构造以后,按照惯例,赋值也要被安排上了。赋值运算符重载实现代码如下:
list<T>& operator =( list<T>& l1){if (this!= &l1){clear();for (auto e : l1){push_back(e);}}return *this;}这是一个传统写法的运算符重载。如果想要更加精简可以写成现代写法,代码如下:
void swap( list<T>& l1)//别加const{std::swap(_head, l1._head);//记得这个swap是std里面的swap}list<T>& operator=(list<T> l1){if (this != &l1){swap(l1);}return *this;}
5.打印函数
在这里,我们每次打印一个list对象时会很麻烦,每次都要用范围for来实现打印的功能。为了偷懒,我就想实现一个打印函数print来实现打印功能。实现代码如下:
template<class T>void print(list<T>& l1){typename list<T>::iterator it = l1.begin();//这里要用typename为前缀来告诉编译器等list<T>实例化以后再来执行这条语句for (auto e : l1){cout << e << " ";}cout << endl;}但是上面的代码针对的类型时list类的泛型,如果想要实现能加载更多容器的print()函数那就得改一下类型,改为如下代码:
template <class Contains>void print(Contains& l1){typename Contains::iterator it = l1.begin();for (auto e : l1){cout << e << " ";}cout << endl;}
相关文章:
Cpp学习——list的模拟实现
目录 一,实现list所需要包含的三个类 二,三个类的实现 1.list_node 2.list类 3.iterator_list类 三,功能实现 1.list类里的push_back() 2.iterator类里的运算符重载 3,list类里面的功能函数 1.insert(ÿ…...
工具推荐:Chat2DB一款开源免费的多数据库客户端工具
文章首发地址 Chat2DB是一款开源免费的多数据库客户端工具,适用于Windows和Mac操作系统,可在本地安装使用,也可以部署到服务器端并通过Web页面进行访问。 相较于传统的数据库客户端软件如Navicat、DBeaver,Chat2DB具备了与AIGC…...
C语言刷题指南(二)
📙作者简介: 清水加冰,目前大二在读,正在学习C/C、Python、操作系统、数据库等。 📘相关专栏:C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 👍…...
[C++11]
文章目录 1. 自动类型推导1.1 auto1.1.1 推导规则1.1.2 auto的限制1.1.3 auto的应用1.1.4 范围for 1.2 decltype1.2.1 推导规则1.2.2 decltype的应用 1.3 返回类型后置 2.可调用对象包装器、绑定器2.1 可调用对象包装器2.1.1 基本用法2.1.2 作为回调函数使用 2.2 绑定器 3. usi…...
【MySQL系列】--初识数据库
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
Unity导入google.protobuf失败,无法找到google命名空间
问题: 1.刚开始把protobuf的文件夹直接从其他项目里(unity2021)里复制到unity(2020)版本,当时报错protobuf.dll的依赖项system.memory版本不对。 2.没有使用原来的protobuf文件了。使用vs2019的NuGet管理包来下载Google.Protobuf ,仍然报错找…...
使用IDM下载视频出现“由于法律原因,IDM无法下载...
一、问题描述 由于法律原因,IDM无法下载..,如图: 二、原因分析 下载该IDM抓取的M3U8文件,查看其中的内容发现 : #EXT-X-KEY 字段已经写明了加密方式是AES-128,包含一个URI和IV值 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:8 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:…...
pointnet C++推理部署--tensorrt框架
classification 如上图所示,由于直接export出的onnx文件有两个输出节点,不方便处理,所以编写脚本删除不需要的输出节点193: import onnxonnx_model onnx.load("cls.onnx") graph onnx_model.graphinputs graph.inpu…...
34.Netty源码之Netty如何处理网络请求
highlight: arduino-light 通过前面两节源码课程的学习,我们知道 Netty 在服务端启动时会为创建 NioServerSocketChannel,当客户端新连接接入时又会创建 NioSocketChannel,不管是服务端还是客户端 Channel,在创建时都会初始化自己…...
vscode 安装勾选项解释
1、通过code 打开“操作添加到windows资源管理器文件上下文菜单 :把这个两个勾选上,可以对文件使用鼠标右键,选择VSCode 打开。 2、将code注册为受支持的文件类型的编辑器:不建议勾选,这样会默认使用VSCode打开支持的相…...
Spring 6.0官方文档示例(24): replace-method的用法
一、原始bean定义 package cn.edu.tju.study.service.anno.domain;public class MyValueCalculator {public String computeValue(String input) {return "you inputted: " input;}// some other methods... }二、replace bean定义 package cn.edu.tju.study.serv…...
自然语言处理从入门到应用——LangChain:记忆(Memory)-[聊天消息记录]
分类目录:《自然语言处理从入门到应用》总目录 Cassandra聊天消息记录 Cassandra是一种分布式数据库,非常适合存储大量数据,是存储聊天消息历史的良好选择,因为它易于扩展,能够处理大量写入操作。 # List of contact…...
Python web实战之细说 Django 的单元测试
关键词: Python Web 开发、Django、单元测试、测试驱动开发、TDD、测试框架、持续集成、自动化测试 大家好,今天,我将带领大家进入 Python Web 开发的新世界,深入探讨 Django 的单元测试。通过本文的实战案例和详细讲解ÿ…...
pytorch 42 C#使用onnxruntime部署内置nms的yolov8模型
在进行目标检测部署时,通常需要自行编码实现对模型预测结果的解码及与预测结果的nms操作。所幸现在的各种部署框架对算子的支持更为灵活,可以在模型内实现预测结果的解码,但仍然需要自行编码实现对预测结果的nms操作。其实在onnx opset===11版本以后,其已支持将nms操作嵌入…...
【Lua】(一)VSCode 搭建 Lua 开发环境
前言 最近在找工作,基本所有的岗位都会问到 Lua(甚至拼 UI 的都要求会 Lua),咱能怎么办呢,咱也只能学啊…… 工欲善其事,必先利其器。第一步,先来把环境配置好吧! 当前适用版本&a…...
react-vite-antd环境下新建项目
vite 创建一个react项目 1. 安装vite并创建一个react项目1. 我使用的 yarn安装,基本配置项目名字, 框架react ,js2. cd vite-react进入项目目录安装node包并启动项目 2. 安装引入Ant Design引入依赖(我用的yarn,没有安装的也可以使…...
KeilMDk软仿真设置_STM32F03C8
1、KeilMDK软仿真的价值 (1)在没有硬件的情况下进行程序的编写调试。 (2)避免频繁的下载程序,延长单片机Flash寿命。 2、软仿真配置。 (1)打开Keil工程。 (2)点击“Options for Target ***”,如下图所示。 (3)点击“Debug”。 (4)进行如下配置。 U…...
mysql的隐式连接和显式连接的区别
隐式连接(Implicit Join)和显式连接(Explicit Join)是 SQL 查询中用于联结多个表的两种不同语法方式。它们的区别主要体现在语法的书写风格和可读性上。 隐式连接: 隐式连接使用逗号 , 将多个表名放在 FROM 子句中&am…...
vue-element-admin新增view后点击侧边栏加载慢问题
按照官网文档新增view 新增之后点击显示一直在加载中 解决方案:删除script中这段代码...
论文《LoRA: Low-Rank Adaptation of Large Language Models》阅读
论文《LoRA: Low-Rank Adaptation of Large Language Models》阅读 BackgroundIntroducitonProblem StatementMethodology Δ W \Delta W ΔW 的选择 W W W的选择 总结 今天带来的是由微软Edward Hu等人完成并发表在ICLR 2022上的论文《LoRA: Low-Rank Adaptation of Large Lan…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...

