STL中list的模拟
这里写目录标题
- list 的节点 —— ListNode
- list 的 “导览员” —— ListIterator
- list 的核心 —— list 类
- 构造函数
- 迭代器相关操作
- 容量相关操作
- 结尾
在 C++ 的 STL(标准模板库)中,list 是一个十分重要的容器,它就像一个灵活的弹簧,可以在任意位置快速地插入和删除元素。今天,就让我们一起走进 list 的世界,去探索它的奥秘。
list 的节点 —— ListNode
template<class T>struct ListNode{ListNode(const T& val = T()):_pPre(nullptr),_pNext(nullptr),_val(val){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};
list 的基础是节点,就像一串项链上的珠子。代码中的 ListNode 就承载着这样的角色。每个节点都有一个前驱指针 _pPre、一个后继指针 _pNext 和一个存储数据的 _val。它们就像是珠子的连接线,将一个个数据串联起来,构成了 list 的主体。当我们创建一个节点时,它就像一颗独立的珠子,等待被加入到项链中。
list 的 “导览员” —— ListIterator
//List的迭代器类template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;//成员函数ListIterator(PNode pNode = nullptr):_pNode(pNode){}ListIterator(const Self& l)//怎么实现拷贝{_pNode = l._pNode;}T& operator*(){return _pNode->_val;}//T* operator->()//存疑//{// return &_pNode->_val;//}Self& operator++(){_pNode= _pNode->_pNext;return *this;}Self operator++(int){Self tmp(*this);_pNode = _pNode->_pNext;return tmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){Self tmp(*this);_pNode = _pNode->_pPre;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return _pNode == l._pNode;}//成员对象PNode _pNode;};
有了节点,我们还需要一个 “导览员” 来带我们游览整个 list,这就是迭代器 ListIterator。它就像是我们手中的一根细棒,可以指向 list 中的任意一个节点,让我们能够方便地访问和操作元素。
构造函数 :它接受一个节点指针作为参数,默认指向空。这就像我们在开始游览之前,先确定了出发点。
拷贝构造函数 :当遇到一个已经存在的迭代器时,我们可以通过拷贝它的方式,快速地获得一个指向相同节点的迭代器。这就好比看到朋友手中有一个很好的导览路线,我们直接复制过来一样。
解引用操作符(operator*) :通过这个操作符,我们可以轻松地获取当前节点所存储的值。这相当于在游览过程中,我们停下脚步,仔细观察手中的珠子。
自增自减操作符(operator++、operator–) :这两个操作符就像是我们的双脚,可以带着我们在 list 的项链上向前或向后移动,指向下一个或前一个节点。
比较操作符(operator!=、operator==) :它们可以帮助我们判断两个迭代器是否指向同一个节点。这就好比在不同的游览路线中,我们可以比较是否来到了同一个景点。
list 的核心 —— list 类
现在,我们迎来了主角 —— list 类。它就像是一个精心编织的项链,将众多节点串联起来,并提供了一系列方法让我们能够灵活地操作它。
//list类template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;public:///// List的构造list(){CreateHead(); }list(int n, const T& value = T()){CreateHead();PNode cur = _pHead;while (n--){PNode next = new Node(value);cur->_pNext = next;next->_pPre = cur;cur = next;_size++;}cur->_pNext = _pHead;_pHead->_pPre = cur;}template <class Iterator>list(Iterator first, Iterator last){CreateHead();PNode cur = _pHead;while (first != last){PNode next = new Node(*first);cur->_pNext = next;next->_pPre = cur;cur = next;first++;_size++;}cur->_pNext = _pHead;_pHead->_pPre = cur;}list(const list<T> &l){CreateHead();for(auto &a:l){push_back(a);}}list<T>& operator=(const list<T> l){CreateHead();swap(l);return *this;}~list(){clear();delete _pHead;_pHead = nullptr;}///// List Iteratoriterator begin(){return _pHead->_pNext;}iterator end(){return _pHead;}const_iterator begin()const{return _pHead->_pNext;}const_iterator end()const{return _pHead;}///// List Capacitysize_t size()const{return _size;}bool empty()const{return _size == 0;}//// List AccessT& front(){return _pHead->_pNext->_val;}const T& front()const{return _pHead->_pNext->_val;}T& back(){return _pHead->_pPre->_val;}const T& back()const{return _pHead->_pPre->_val;}// List Modifyvoid push_back(const T& val) {insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { insert(begin(), val);}void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){PNode n = new Node(val);PNode pre = pos._pNode->_pPre;pre->_pNext = n;n->_pPre = pre;n->_pNext = pos._pNode;pos._pNode->_pPre = n;_size++;return n;}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){PNode pre = pos._pNode->_pPre;PNode next = pos._pNode->_pNext;delete pos._pNode;pre->_pNext = next;next->_pPre = pre;_size--;return next;}void clear(){PNode cur = _pHead->_pNext;while (cur != _pHead){PNode next = cur->_pNext;delete cur;cur = next;}_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;_size = 0;}void swap(list<T>& l){std::swap(_pHead, l._pHead);std::swap(_size, l._size);}//void print()//{// for (auto c : *this)// {// cout << c << " ";// }// cout << endl;//}private:void CreateHead(){_pHead = new Node;_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;_size = 0;}PNode _pHead;size_t _size;};
};
构造函数
默认构造函数会创建一个头节点 _pHead,它是一个特殊的节点,不存储实际数据,但起到了标记项链开头和结尾的作用。这就像我们在开始制作项链时,先打了个结。
可以指定元素个数和初始值来构造 list。这就像我们已经有了设计图,知道要制作多少颗珠子以及它们的颜色,于是按照这个设计直接把珠子串起来。
还可以从一个范围(通过迭代器指定开始和结束位置)来构造 list。这就像是我们从一个现成的珠子堆中,挑选
出一部分珠子,按照顺序串成项链。
拷贝构造函数能够复制一个已有的 list。这就好比看到了一件精美的项链作品,我们想模仿着制作一个一模一样的。
赋值操作符(operator=) :它通过 “拷贝 - 交换” 技术,先创建一个临时的 list,再与当前 list 进行交换。这就像我们先按照别人的项链样式做好一个新项链,然后把自己的旧项链换掉。
析构函数 :在 list 不再被需要时,析构函数会负责清理内存,删除所有节点,并释放头节点。这是在我们结束了项链的使用后,把它拆解,回收材料的过程。
迭代器相关操作
begin() 和 end() 方法分别返回指向 list 第一个节点和头节点(代表结束位置)的迭代器。这就像我们在游览项链时,确定了起点和终点。
const_iterator 版本的 begin() 和 end() 方法可以让我们在不修改 list 的情况下进行遍历,就像是我们戴着白手套,小心翼翼地观察项链上的珠子,而不去改变它们。
容量相关操作
size() 方法能够返回 list 当前的元素个数。这让我们可以清楚地知道项链上有多少颗珠子。
empty() 方法用于判断 list 是否为空,返回一个布尔值。这就像在检查项链是否已经断开,里面是否还有珠子。
元素访问操作
front() 和 back() 方法分别返回 list 第一个和最后一个元素的引用。这相当于我们直接拿起项链的开端或末端的珠子,查看它的模样。
修改操作
push_back() 和 pop_back() 方法用于在 list 的尾部添加或删除元素。这就像我们在项链的末端添加或取下一颗珠子。
push_front() 和 pop_front() 方法则是在 list 的头部进行添加或删除操作。这类似于我们在项链的开头位置进行珠子的增减。
insert() 方法可以在指定位置前插入一个元素。这就好比我们在项链的某个特定位置插入一颗新的珠子,需要调整相邻珠子的连接关系。
erase() 方法用于删除指定位置的元素,并返回下一个元素的位置。这就像我们在项链上取下一颗珠子后,要把剩下的珠子重新连接起来,并且告诉我们接下来的位置在哪里。
clear() 方法会清除 list 中的所有元素,将项链完全拆解,只剩下头节点。这通常在我们想要重新利用这条项链,重新设计样式时使用。
swap() 方法可以快速地交换两个 list 的内容。这就像我们把两条项链的珠子序列互换,但项链本身的结构(如头节点)保持不变。
结尾
通过以上对 list 的各个组成部分以及其成员函数的详细介绍(虽然这里的代码实现可能与 STL 中的 list 有些许不同,只是起到模拟作用),我们对 list 的工作原理和使用方法有了更深入的理解。它就像是我们手中的一条神奇项链,可以根据我们的需求,在任何位置灵活地添加或删除珠子,为我们处理数据提供了极大的便利。希望这次的 list 之旅能够让你对 C++ STL 有更进一步的认识,让我们在编程的世界里继续探索,发现更多宝藏!
相关文章:
STL中list的模拟
这里写目录标题 list 的节点 —— ListNodelist 的 “导览员” —— ListIteratorlist 的核心 —— list 类构造函数迭代器相关操作容量相关操作 结尾 在 C 的 STL(标准模板库)中,list 是一个十分重要的容器,它就像一个灵活的弹簧…...

6.3.2图的深度优先遍历
知识总览: 树的先根遍历: 采用递归一直找某个节点的子树直到找不到从上往下找 访问根节点1,1的子树有2、3、4,访问2,2节点子树有5访问5,5没有子树,退回到2,2还有子树6访问6,6没有子树再退回到2,2的子树都被访问了再退…...

畅游Diffusion数字人(30):情绪化数字人视频生成
畅游Diffusion数字人(0):专栏文章导航 前言:仅从音频生成此类运动极具挑战性,因为它在音频和运动之间存在一对多的相关性。运动视频的情绪是多元化的选择,之前的工作很少考虑情绪化的数字人生成。今天解读一个最新的工作FLOAT,可以生成制定情绪化的数字人视频。 目录 贡献…...

UE5 Va Res发送请求、处理请求、json使用
文章目录 介绍发送一个Get请求发送Post请求设置请求头请求体带添json发送请求完整的发送蓝图 处理收到的数据常用的json处理节点 介绍 UE5 自带的Http插件,插件内自带json解析功能 发送一个Get请求 只能写在事件图表里 发送Post请求 只能写在事件图表里 设置…...
关于flutter中Scaffold.of(context).openEndDrawer();不生效问题
原因: 在 Flutter 中,Scaffold.of(context) 会沿着当前的 context 向上查找最近的 Scaffold。如果当前的 widget 树层级中没有合适的 Scaffold(比如按钮所在的 context 是在某个子 widget 中),就找不到它。 解决办法…...
【C++】深入理解C++中的函数与运算符重载
文章目录 前言一、什么是重载?1.1 函数重载1.1.1 函数重载的规则1.1.2 示例:函数重载 1.2 运算符重载1.2.1 运算符重载的规则1.2.2 示例:运算符重载 1.2.3 运算符重载的注意事项 二、重载的注意事项2.1 重载的二义性2.2 默认参数和重载2.3 运…...

【读代码】BAGEL:统一多模态理解与生成的模型
一、项目概览 1.1 核心定位 BAGEL是字节跳动推出的开源多模态基础模型,具有70亿激活参数(140亿总参数)。该模型在统一架构下实现了三大核心能力: 多模态理解:在MME、MMBench等9大评测基准中超越Qwen2.5-VL等主流模型文本生成图像:生成质量媲美SD3等专业生成模型智能图像…...

隧道自动化监测解决方案
行业现状 隧道作为一种重要的交通运输通道,不管是缓解交通压力,还是让路网结构更趋于完善,它都有着不可估量的作用。隧道在运营过程中,由于受到材料退化、地震、人为因素等影响会发生隧道主体结构的损坏和劣化。若不及时检修和维护…...
如何通过EventChannel实现Flutter与原生平台的双向通信?
在Flutter开发中,EventChannel是处理单向数据流的核心组件,尤其适用于原生平台(Android/iOS)主动向Flutter端推送实时数据的场景,例如传感器数据、后台任务通知等。虽然EventChannel本身以原生到Flutter的单向通信为主,但结合特定设计模式,仍可实现双向交互。本文将详细…...

游戏引擎学习第307天:排序组可视化
简短谈谈直播编程的一些好处。 上次结束后,很多人都指出代码中存在一个拼写错误,因此这次我们一开始就知道有一个 bug 等待修复,省去了调试寻找错误的时间。 今天的任务就是修复这个已知 bug,然后继续排查其他潜在的问题。如果短…...

java接口自动化初识
简介 了解什么是接口和为什么要做接口测试。并且知道接口自动化测试应该学习哪些技术以及接口自动化测试的落地过程。 一、什么是接口 在这里我举了一个比较生活化的例子,比如我们有一台笔记本,在笔记本的两端有很多插口。例如:USB插口。那…...
工作流引擎-01-Activiti 是领先的轻量级、以 Java 为中心的开源 BPMN 引擎,支持现实世界的流程自动化需求
前言 大家好,我是老马。 最近想设计一款审批系统,于是了解一下关于流程引擎的知识。 下面是一些的流程引擎相关资料。 工作流引擎系列 工作流引擎-00-流程引擎概览 工作流引擎-01-Activiti 是领先的轻量级、以 Java 为中心的开源 BPMN 引擎&#x…...
时序数据库IoTDB的分片与负载均衡策略深入解析
一、引言 随着数据库服务的业务负载增加,扩展服务资源成为必然需求。扩展方式主要分为纵向扩展和横向扩展。纵向扩展通过增加单台机器的能力(如内存、硬盘、处理器)来实现,但受限于单台机器的硬件能力。而横向扩展则通过增加更多…...

NVM安装使用及问题解决
目录 一、前言 二、NVM安装 三、配置下载源 四、nvm使用 五、安装nvm list available没有的版本 六、问题解决 一、前言 如果你开发 Node.js 项目,可能会遇到这些问题: ①新项目需要 Node.js 18,但老项目只能用 Node.js 14,…...

C++学习之STL学习:string类使用
在之前的学习中,我们初步了解到了STL的概念,接下来我们将深入学习STL中的string类的使用,后续还会结合他们的功能进行模拟实验 目录 为什么要学习string类? 标准库中的string类 string类(了解) auto和范围…...
基于 STC89C52 的养殖场智能温控系统设计与实现
摘要 本文提出一种基于 STC89C52 单片机的养殖场环境温度智能控制系统,通过集成高精度温度传感器、智能执行机构及人机交互模块,实现对养殖环境的实时监测与自动调控。系统具备温度阈值设定、超限报警及多模式控制功能,可有效提升养殖环境稳定性,降低能耗与人工成本。 一…...
redis哨兵服务
配置主机Host67为master服务器配置主机host68为 slave服务器配置主机host69运行哨兵服务测试配置 IP地址主机名192.168.10.167redis167192.168.10.168redis168192.168.10.169redis169 步骤一:配置主机Host67为master服务器 [rootredis169 ~]# vim /etc/redis.c…...

5月24日day35打卡
模型可视化与推理 知识点回顾: 三种不同的模型可视化方法:推荐torchinfo打印summary权重分布可视化进度条功能:手动和自动写法,让打印结果更加美观推理的写法:评估模式 作业:调整模型定义时的超参数&#x…...
嵌入式<style>设计模式
每天分享一个web前端开发技巧。 今天分享的主题是,如何提升前端代码的内聚性。我们在写<style></style>的时候,往往把大量无关联的样式写在同一个<style>下,而且离相关的html元素很远,这样导致每次想修改某个元…...
Kotlin 中该如何安全地处理可空类型?
在 Kotlin 中,可空类型(如 String?)是语言设计的核心特性之一,旨在从编译时避免 NullPointerException(NPE)。 1 核心处理方式 1.1 安全调用操作符(?.) 直接调用可空对象的方法…...
基于大模型预测的视神经脊髓炎技术方案
目录 一、术前评估与预测1. 数据采集与预处理2. 大模型构建与训练3. 术前风险评估与预测二、术中监测与决策支持1. 实时数据采集与传输2. 术中决策支持系统三、术后管理与康复1. 术后早期预警与监测2. 康复效果预测与个性化方案四、并发症风险预测与防控1. 并发症风险预测模型2…...
使用防火墙禁止程序联网(这里禁止vscode)
everything搜一下Code.exe的安装路径:D:\downloadApp1\vscode\Microsoft VS Code\Code.exe 方法:使用系统防火墙(推荐) Windows 通过防火墙阻止 VS Code: 打开 Windows Defender 防火墙(控制面板 > 系统…...

Linux(7)——进程(概念篇)
目录 一、基本概念 二、描述进程——PCB 1.task_struct——PCB的一种 2.task_struct的内容分类 三、查看进程 1.通过系统目录查看 2.通过ps命令查看 四、通过系统调用获取进程的PID和PPID 五、通过系统调用创建进程 1.fork函数创建子进程 2.使用if来引出问题 六、L…...

前端流行框架Vue3教程:24.动态组件
24.动态组件 有些场景会需要在两个组件间来回切换,比如 Tab 界面 我们准备好A B两个组件ComponentA ComponentA App.vue代码如下: <script> import ComponentA from "./components/ComponentA.vue" import ComponentB from "./…...

Unity3D仿星露谷物语开发48之显示树桩效果
1、目标 砍完橡树之后会露出树桩,然后树桩可以用斧头收割,并将创建一个新的砍树桩的粒子效果。 这里有:一种作物收获后创造另一种作物的逻辑。 2、分析 在SO_CropDetailsList中,Harvested Transform Item Code可以指定收获后生…...

[Datagear] 实现按月颗粒度选择日期的方案
在使用 Datagear 构建数据分析报表时,常常会遇到一个问题:如果数据的目标颗粒度是“月”,默认的日期控件却是精确到“日”的,这在用户交互和数据处理层面会带来不必要的复杂度。本文将分享两种解决方案,帮助你更好地控制日期控件的颗粒度,实现以月为单位的日期筛选功能。…...

漏洞检测与渗透检验在功能及范围上究竟有何显著差异?
漏洞检测与渗透检验是确保系统安全的重要途径,这两种方法各具特色和功效,它们在功能上有着显著的差异。 目的不同 漏洞扫描的主要任务是揭示系统内已知的安全漏洞和隐患,这就像是对系统进行一次全面的健康检查,看是否有已知的疾…...

DB-GPT扩展自定义Agent配置说明
简介 文章主要介绍了如何扩展一个自定义Agent,这里是用官方提供的总结摘要的Agent做了个示例,先给大家看下显示效果 代码目录 博主将代码放在core目录了,后续经过对源码的解读感觉放在dbgpt_serve.agent.agents.expand目录下可能更合适&…...
基于SamOutV8的序列生成模型实现与分析
项目概述 本项目实现了基于SamOutV8架构的序列生成模型,核心组件包括MaxStateSuper、FeedForward和DecoderLayer等模块。通过结合自注意力机制与状态编码策略,该模型在处理长序列时表现出良好的性能。 核心组件解析 1. MaxStateSuper(状态编…...

家政维修平台实战09:推送数据到多维表格
目录 1 API调试2 创建云函数3 前端调用整体效果总结 上一篇我们搭建了服务分类的后台功能,对于分类的图标通过集成TOS拿到了可以公开访问的地址,本篇我们将写入的数据推送至多维表格中。 1 API调试 要想推送多维表格的数据,首先要利用官方的…...