C++ list链表模拟实现
目录
前言:
模拟实现:
迭代器的实现:
list类功能函数实现:
初始化成空函数(empty_init):
构造函数:
拷贝构造函数:
尾插(push_back):
插入(insert):
删除(erase):
尾删(pop_back):
头插(push_front):
头删(pop_front):
清理(clear):
交换(swap):
赋值重载:
析构:
代码
前言:
在学习完list的基本功能后,我自己模拟实现了一个list,具备一些常用的基本功能,这篇博客用来分享并记录,方便后续复习。
模拟实现:
因为list中可以存很多种类型,比如int,char,float,等,还可能是自定义类型,所以我打算使用类模板,先把简单的节点弄成类模板:

接下来就是list的类模板:

迭代器的实现:
这里迭代器的模拟实现不能像vector一样简单的使用原生指针,因为链表的地址不是连续的,我们在进行原生指针的++或者--操作时,是无法实现访问下一个或者上一个元素的,那该怎样实现简单的对迭代器++或者--就能实现访问下一个或者上一个元素呢?
这里有一个巧妙地方法就是借助类,没错,我们将原生指针放入一个名为Listiterator的类里面,然后在这个类中,使用运算符重载,重载++,--,*,->等运算符,就能像库里面一样使用迭代器了。

上图的Ref和Ptr模板分别是传引用和传指针,用于应对const 迭代器的使用 ,保证const迭代器可以修改迭代器,但不能修改该迭代器指向的内容。接下来开始在这个类中重载各种运算符:

这几个运算符重载都很简单,应该都能看懂,接下来进入list类模板中,就行list的功能函数实现:
list类功能函数实现:
先来几个简单但又很重要的函数实现:

初始化成空函数(empty_init):

构造函数:
有了上面这个函数后,构造函数就简单了,直接复用即可:

拷贝构造函数:

尾插(push_back):

插入(insert):

删除(erase):

尾删(pop_back):

头插(push_front):

头删(pop_front):

清理(clear):

交换(swap):

赋值重载:

此处传值传参的妙处:
list1=iist2,进入函数此时lt是list2的拷贝,因为swap是成员函数,所以有一个隐含的this指针,此时只需传参lt就可以完成lt和list1交换,间接完成对list1的赋值,同时没有改变list2,只是改变了lt,而lt出作用域后就会消失。
析构:

代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
namespace sxk
{ template<class T>struct ListNode{ListNode<T>* next;//下一个节点的地址ListNode<T>* prev;//上一个节点的地址T val;//数据ListNode(const T& x = T())//节点的构造函数:next(nullptr), prev(nullptr), val(x){}};template<class T,class Ref,class Ptr>struct Listiterator{typedef ListNode<T> Node;typedef Listiterator<T, Ref, Ptr> Self;typedef Listiterator<T, T&, T*> iterator;typedef Listiterator<T, const T&, const T*> const_iterator;Node* _node;Listiterator(Node* node)//迭代器的构造函数:_node(node){}Ref operator*(){return _node->val;}Ptr operator->(){return &_node->val;}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){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}};template<class T>class list{public:typedef ListNode<T> Node;typedef Listiterator<T, T&, T*> iterator;typedef Listiterator<T, const T&, const T*> const_iterator;iterator begin(){return _head->next;}iterator end(){return _head;}const_iterator begin()const{return _head->next;}const_iterator end()const{return _head;}size_t size(){return _size;}bool empty(){return _size == 0;}void empty_init(){_head = new Node;//new出头节点_head->next = _head;//头节点下一个指向自己_head->prev = _head;//头节点上一个指向自己_size = 0;}list()//构造函数{empty_init();}list(const list<T>& lt)//拷贝构造函数{empty_init();//先初始化成只有一个头节点for (auto& x : lt){push_back(x);//直接尾插即可}}list<T>& operator=(const list<T> lt)//lt是赋值类的拷贝{swap(lt);//交换lt和this,可以完成赋值并不影响赋值类return *this;}void swap(const list<T>& lt){std::swap(_head, lt._head);//直接调用库里的swap交换两个成员变量即可std::swap(_size, lt._size);}void clear(){iterator it = begin();while (it != end())//遍历删除{it = erase(it);//更新it,防止erase后迭代器失效it++;}}~list(){clear();//先清理,只保留一个头节点delete _head;//释放头节点_head = nullptr;}void push_back(const T& x){Node* newnode = new Node;//new出新节点newnode->val = x;//给新节点赋值Node* tail = _head->prev;//记录尾节点tail->next = newnode;//尾节点的下一个指向新节点newnode->next = _head;//新节点的next指向头节点newnode->prev = tail;//新节点的prev指向之前旧的尾节点_head->prev = newnode;//头节点的prev指向新节点_size++;}void push_front(){insert(begin());}void pop_back(){erase(--end());//直接复用erase,注意end指向的是头节点,所以要--}void pop_front(){erase(begin());}void insert(iterator pos, const T& x)//在pos位置前插入x{Node* newnode = new Node;//new出新节点newnode->val = x;//给新节点赋值Node* cur = pos._node;//记录当前pos位置Node* prev = cur->prev;//记录pos前一个prev->next = newnode;//pos前一个节点的next指向新节点newnode->next = cur;//新节点的next指向pos节点newnode->prev = prev;//新节点的prev指向pos前一个节点cur->prev = newnode;//pos的prev指向新节点_size++;}iterator erase(iterator pos)//删除pos位置的值{Node* cur = pos._node;//记录pos位置的节点Node* prev = cur->prev;//记录pos的前一个节点Node* next = cur->next;//记录pos的下一个节点prev->next = cur->next;//pos的前一个节点的next指向pos的下一个节点next->prev = prev;//pos的下一个节点的prev指向pos的前一个节点delete cur;//释放pos位置的节点cur = nullptr;//置为空_size--;return iterator(next);//防止erase后迭代器失效,更新迭代器}private:Node* _head;size_t _size;};void Print_List(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){cout << (*it) << " ";it++;}cout << endl;}
}相关文章:
C++ list链表模拟实现
目录 前言: 模拟实现: 迭代器的实现: list类功能函数实现: 初始化成空函数(empty_init): 构造函数: 拷贝构造函数: 尾插(push_back): 插入…...
LangChain - PromptTemplate
文章目录 关于 Prompt关于 PromptTemplate基本创建无变量输入1个变量多变量使用 from_template 自动推断 input_variables 聊天模板使用 from_template 方法构建使用 PromptTemplate 构建 MessagePromptTemplate使用一或多个 MessagePromptTemplates 构建一个 ChatPromptTempla…...
spring cloud gateway openfeign 联合使用产生死锁问题
spring cloud gateway openfeign 联合使用产生死锁问题,应用启动的时候阻塞卡住。 spring.cloud 版本如下 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><vers…...
【WPF应用37】WPF基本控件-DatePicker的详解与示例
WPF(Windows Presentation Foundation)是微软推出的一个用于构建桌面应用程序的图形子系统。在WPF中,DatePicker控件是一个常用的控件,用于用户选择日期。DatePicker控件提供了一个简洁直观的界面,使用户能够轻松选择日…...
GitHub教程:最新如何从GitHub上下载文件(下载单个文件或者下载整个项目文件)之详细步骤讲解(图文教程)
🐯 GitHub教程:最新如何从GitHub上下载文件(下载单个文件或者下载整个项目文件)之详细步骤讲解(图文教程) 📁 文章目录 🐯 GitHub教程:最新如何从GitHub上下载文件(下载单个文件或者下载整个项目文件)之详细步骤讲解(图…...
编译Nginx配置QUIC/HTTP3.0
1. 安装BoringSSL sudo apt update sudo apt install -y build-essential ca-certificates zlib1g-dev libpcre3 \ libpcre3-dev tar unzip libssl-dev wget curl git cmake ninja-build mercurial \ libunwind-dev pkg-configgit clone --depth1 https://github.com/google/b…...
【JavaWeb】Day38.MySQL概述——数据库设计-DQL
数据库设计——DQL 介绍 DQL英文全称是Data Query Language(数据查询语言),用来查询数据库表中的记录。 查询关键字:SELECT 查询操作是所有SQL语句当中最为常见,也是最为重要的操作。在一个正常的业务系统中,查询操作的使用频次…...
如何使用Java和RabbitMQ实现延迟队列(方式二)?
前言 昨天写了一篇关于Java和RabbitMQ使用插件实现延迟队列功能的文章,今天来讲下另外一种方式,不需要RabbitMQ的插件。 前期准备,需要安装好docker、docker-compose的运行环境。 需要安装RabbitMQ的可以看下面这篇文章。 如何使用PHP和R…...
String.valueOf() 将各种数据类型的值转换为它们的字符串
String.valueOf() 是 Java 中 String 类的一个静态方法,用于将各种数据类型的值转换为它们的字符串表示形式。这个方法在多种情况下都非常有用,特别是当你需要将非字符串类型的值转换为字符串时。 方法签名 String.valueOf() 方法有多个重载版本&#…...
2024-04-08 NO.6 Quest3 自定义交互事件
文章目录 1 交互事件——更改 Cube 颜色2 交互事件——创建 Cube2.1 非代码方式2.2 代码方式 在开始操作前,我们导入上次操作的场景,相关介绍在 《2024-04-08 NO.5 Quest3 手势追踪进行 UI 交互-CSDN博客》 文章中。 1 交互事件——更改 Cube 颜色 …...
素描进阶:深入探索如何表现石膏像的质感
素描进阶:深入探索如何表现石膏像的质感 素描,作为一种古老而经典的绘画方式,历来都被视为是艺术家们探索世界、理解形式与质感的重要工具。而在素描的过程中,如何精准地捕捉并表现物体的质感,是每位艺术家都需要深…...
flutter组件_AlertDialog
官方说明:A Material Design alert dialog. 翻译:一个材料设计警告对话框。 作者释义:显示弹窗,类似于element ui中的Dialog组件。 AlertDialog的定义 const AlertDialog({super.key,this.icon,this.iconPadding,this.iconColor,t…...
供应链领域主题:生产制造关键术语和系统
BOM(Bill of Material)物料清单 BOM(Bill of Material)物料清单,是计算机可以识别的产品结构数据文件,也是ERP的主导文件。BOM使系统识别产品结构,也是联系与沟通企业各项业务的纽带。ERP系统中…...
k8s_入门_kubelet安装
安装 在大致了解了一些k8s的基本概念之后,我们实际部署一个k8s集群,做进一步的了解 1. 裸机安装 采用三台机器,一台机器为Master(控制面板组件)两台机器为Node(工作节点) 机器的准备有两种方式…...
主干网络篇 | YOLOv5/v7 更换骨干网络之 HGNetv2 | 百度新一代超强主干网络
本改进已融入到 YOLOv5-Magic 框架。 论文地址:https://arxiv.org/abs/2304.08069 代码地址:https://github.com/PaddlePaddle/PaddleDetection 中文翻译:https://blog.csdn.net/weixin_43694096/article/details/131353118 文章目录 HGNetv2网络结构1.1 主干网络1.2 颈部…...
JUC:ScheduledThreadPoolExecutor 延迟任务线程池的使用
文章目录 ScheduledThreadPoolExecutortimer(不建议用)ScheduledThreadPoolExecutor处理异常应用 ScheduledThreadPoolExecutor timer(不建议用) timer也可以进行延迟运行,但是会有很多问题。 比如task1运行时间超过…...
js str字符串和arr数组互相转换
js str字符串和arr数组互相转换 字符串转为数组 1、split()方法 返回的是原字符串的数组 var str "hello"; var arr str.split(""); console.log(arr); //输出["h", "e", "l", "l", "o"]2、Ar…...
计算机网络——40各个层次的安全性
各个层次的安全性 安全电子邮件 Alice需要发送机密的报文m给Bob Alice 产生随机的对称秘钥, K s K_s Ks使用 K s K_s Ks对报文进行加密(为了效率)对 K s K_s Ks使用Bob的公钥进行加密发送 K s ( m ) K_s(m) Ks(m)和 K B ( K S ) K…...
OpenHarmony实战:Combo解决方案之W800芯片移植案例
本方案基于OpenHarmony LiteOS-M内核,使用联盛德W800芯片的润和软件海王星系列Neptune100开发板,进行开发移植。 移植架构采用Board与SoC分离方案,支持通过Kconfig图形化配置编译选项,增加玄铁ck804ef架构移植,实现了…...
【数据结构】数组(稀疏矩阵、特殊矩阵压缩、矩阵存储、稀疏矩阵的快速转置、十字链表)
稀疏矩阵、矩阵压缩、稀疏矩阵的快速转置、十字链表 目录 稀疏矩阵、矩阵压缩、稀疏矩阵的快速转置、十字链表1.数组2.数组的顺序表示和实现3.特殊矩阵的压缩存储(1). 上三角矩阵—列为主序压缩存储(2). 下三角矩阵—**行为主序压…...
Python项目依赖管理:如何用pipreqs精准生成requirements.txt(附常见问题解决)
Python项目依赖管理实战:从pipreqs到高效协作的全链路优化 在Python项目开发中,依赖管理就像建筑的地基——它不显眼却决定了整个项目的稳定性。想象一下这样的场景:你花了三天时间调试一个诡异的问题,最后发现只是因为测试环境缺…...
Ubuntu 20.04下Mathematica 12.3安装全攻略(附Jupyter集成技巧)
Ubuntu 20.04下Mathematica 12.3安装与Jupyter集成实战指南 在科研计算与符号数学领域,Mathematica始终保持着不可替代的地位。对于Ubuntu用户而言,安装特定历史版本(如12.3)往往比最新版本更具挑战性——官方默认提供最新版下载&…...
Claude Code开源第一人,竟是华人辍学博士!CC之父回应:纯手误
51万行Claude Code代码全网裸奔,背后泄密第一人竟是他。就在刚刚,CC之父回应来了:是人,不是Bun。爆出Claude Code源码第一人,竟被全网扒出来了!3月31日凌晨4点23分,安全研究员Chaofan Shou在X上…...
嵌入式开发关键技术演进与实战经验分享
1. 嵌入式开发的行业现状与核心挑战2023年的嵌入式开发领域呈现出明显的多元化发展趋势。作为一名从业超过十年的嵌入式工程师,我观察到这个行业正在经历从传统单机设备向智能化、网络化方向的快速转型。根据AspenCore最新发布的行业调查报告,目前超过30…...
米哈游面经规律总结:我看了大量面经,挂掉的人都卡在同一层
米哈游面经规律总结:我看了大量面经,挂掉的人都卡在同一层 offer直通车-校招大礼包获取:入口 几乎所有挂掉的人,都挂在同一个地方 最近整理米哈游的面经,看到一个反复出现的场面。 面试官问:"说说智…...
【OpenClaw从入门到精通】第54篇:物理隔离“龙虾”——傻福虾盘与Docker沙箱实战对比(2026实测版)
摘要:2026年工信部NVDB平台及CNCERT指南明确要求:OpenClaw需在隔离环境中部署,严禁在办公设备直接运行。本文聚焦两大主流隔离方案——物理隔离(闲置旧电脑/专用硬件盒子)与Docker沙箱,系统拆解从原理到实操的全流程。包含3套完整部署案例、15+安全配置命令、容器逃逸风险…...
TX12 + ExpressLRS 915MHz RC链路优化与EdgeTX固件升级实战
1. 为什么选择TX12搭配ExpressLRS 915MHz系统 玩无人机的朋友都知道,遥控链路就像风筝线,距离和稳定性直接决定飞行体验。我之前用2.4GHz的RadioLink套装,飞到500米就开始心跳加速——信号时断时续,每次返航都像在赌运气。换成TX1…...
随着AI和电商重塑消费者购买行为,全球美妆市场增长10%
随着数字优先和AI影响下的全球电商加速发展,线上销售额增速达到线下门店的6倍 全球消费者情报领军企业NielsenIQ (NYSE:NIQ)今日发布《2026年美妆行业现状报告》。报告显示,全球美妆市场同比增长10%,电商销售额增速达到线下门店的6倍。该结果…...
革新游戏配置体验:PCL2-CE社区版,Minecraft玩家的效率神器
革新游戏配置体验:PCL2-CE社区版,Minecraft玩家的效率神器 PCL2-CE社区版是一款开源游戏配置工具,它不仅能让玩家轻松管理Minecraft游戏环境,更能通过智能时间管理、跨平台同步等功能,为玩家节省宝贵的游戏时间&#…...
攻克模电难点(一):多级放大电路与差动放大电路实战解析
1. 多级放大电路的设计基础 第一次接触多级放大电路时,我被各种耦合方式绕得头晕。直到在实验室烧坏几个三极管后,才真正理解其中的门道。多级放大电路的核心思想很简单:把多个单级放大电路像搭积木一样连接起来,但实际设计时却要…...
