STL:List从0到1


🎉个人名片:
🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————
🎉文章简介:
🎉本篇文章将 介绍如何使用C++编写代码来实现一个类似于STL中的List容器 相关知识进行分享!
💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
——————————————————
一.前言
这篇文章将介绍如何使用C++编写代码来实现一个类似于STL中的List容器。 list是一个可以在常数范围内在任意位置进行插入和删除的序列式容器。在这篇文章中,你将学习并实现List的常见功能,如添加元素、删除元素等。通过实现自己的List容器,你将更好地熟悉List的使用及相关特性,并提升对C++语言的理解和掌握。
————————————————
二.List的介绍
List文档介绍链接: link
1. list是一个可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代;
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素;
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效;
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好(不需要挪动数据);
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素);
三.List的结构及模拟实现
一.底层结构
List底层是一个带头双向循环链表
如图:


库里面的begin() 与end() 返回的节点位置:
begin()返回的是头节点的下一个节点;
而end()返回的是头节点;
二.List的模拟实现
重点::迭代器的实现
1. 构造函数
template<class T>
struct ListNode
{ListNode<T>(const T& x=T()) :_next(nullptr),_prev(nullptr),_val(x){}ListNode<T>* _next;ListNode<T>* _prev;T _val;
};
库里面的List类的构造函数是另写一个函数,因为这个函数拷贝构造会使用,然后复用它,所以我们也这样实现;
template<class T>
class List
{
public:void empty_List(){_phead = new node;_phead->_next = _phead;_phead->_prev = _phead;}List(){empty_List();}
}
2. 拷贝构造函数
List(const List<T>& lt)
{empty_List(); //初始化for (const auto& e : lt) {push_back(e); //将lt里面的数据依次尾插}
}
3. 插入函数
思路:记录前一个和后一个节点,然后连接

iterator insert(iterator pos, const T& x)
{node* newnode = new node(x); //构造一个节点node* next = pos._node; node* prev = next->_prev; //记录前一个newnode->_next = next; next->_prev = newnode; //链接newnode->_prev = prev;prev->_next = newnode;return pos;
}
4. 尾插函数
复用insert函数
void push_back(const T& x)
{
/* node* newnode = new node(x);node* tail = _phead->_prev;tail->_next = newnode;newnode->_prev = tail; //不复用的写法newnode->_next = _phead;_phead->_prev = newnode;*/insert(end(), x);
}
5. 头插函数
复用insert函数
void push_front(const T& x){insert(begin(),x);}
6. 删除函数
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; //释放掉该节点return next; //返回删除元素的下一个节点
}
7. 尾删函数
复用删除函数
void pop_back(){//erase(end()._node->_prev);erase(--end()); //头节点的前指针指向的是最后一个节点}
8. 头删函数
复用删除函数
void pop_front(){erase(begin()); }
9. 迭代器的实现
因为链表的底层物理空间不是连续的,所以不能使用原生指针类实现。因为原生指针++,可以找到下一个数据,但是链表的节点与节点之间不是连续的,指针++,不能找到下一个节点,所以我们需要操作符重载,改变 ++, != ,* 等操作符的行为;又因为节点指针是内置类型,不能进行操作符重载,所以我们只能将它进行封装,封装在一个类里面,进行重载;
template<class T>
struct __List_iterator
{typedef ListNode<T> node;typedef __List_iterator<T> self;__List_iterator(node* node) //构造函数:_node(node){}self& operator++() //运算符的重载{_node = _node->_next; //前置++,返回++后的值return *this;}self& operator++(int){self tmp(_node); //保存++前的值_node = _node->_next;return tmp; //返回++前的值}self& operator--(){_node = _node->_prev;return *this;}self& operator--(int){self tmp(_node);_node = _node->_prev;return tmp;}T& operator*(){return _node->_val;}bool operator!=(const self& s){return s._node!= this->_node;}bool operator==(const self& s){return s._node == this->_node;}node* _node;
};
10. 赋值运算符重载
传统写法:
void clear(){iterator lt = begin();while (lt != end()){lt = erase(lt);}}
//lt1=lt2
List<T>& operator=(const List<T>& lt)
{clear(); //清空函数,将链表中的有效数据删除掉,保留头节点for (const auto& e : lt){push_back(e); //依次尾插}return *this;
}
现代写法:
void swap(List<T>& lt)
{std::swap(_phead, lt->_phead);
}
//lt1=lt2
List<T>& operator=(List<T> lt) //lt是lt2的拷贝构造
{swap(lt); //交换lt与lt1return *this; //返回
}
补充知识:
typedef 放在类里面与外面的区别:
如果是放在公有里面,则类外面也可以使用,但是要指定类域;
如果是私有的话,则类外面不能使用;
三.总代码:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;namespace L
{template<class T>struct ListNode{ListNode<T>(const T& x=T()):_next(nullptr),_prev(nullptr),_val(x){}ListNode<T>* _next;ListNode<T>* _prev;T _val;};template<class T>struct __List_iterator{typedef ListNode<T> node;typedef __List_iterator<T> self;__List_iterator(node* node):_node(node){}self& operator++(){_node = _node->_next;return *this;}self& operator++(int){self tmp(_node);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self& operator--(int){self tmp(_node);_node = _node->_prev;return tmp;}T& operator*(){return _node->_val;}bool operator!=(const self& s){return s._node!= this->_node;}bool operator==(const self& s){return s._node == this->_node;}node* _node;};template<class T>class List{public:typedef ListNode<T> node;typedef __List_iterator<T> iterator;iterator begin(){return iterator(_phead->_next);}iterator end(){return iterator(_phead);}void empty_List(){_phead = new node;_phead->_next = _phead;_phead->_prev = _phead;}List(){empty_List();}List(const List<T>& lt){empty_List();for (const auto& e : lt) //引用更好,如果T类型是自定义类型的话{push_back(e);}}//lt1=lt2List<T>& operator=(const List<T>& lt){clear();for (const auto& e : lt){push_back(e);}return *this;}void swap(List<T>& lt){std::swap(_phead, lt->_phead);}//lt1=lt2List<T>& operator=(List<T> lt){swap(lt);return *this;}void clear(){iterator lt = begin();while (lt != end()){lt = erase(lt);}}~List(){clear();delete _phead;_phead = nullptr;}void push_back(const T& x){/* node* newnode = new node(x);node* tail = _phead->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _phead;_phead->_prev = newnode;*/insert(end(), x);}void push_front(const T& x){insert(begin(),x);}iterator insert(iterator pos, const T& x){node* newnode = new node(x);node* next = pos._node;node* prev = next->_prev;newnode->_next = next;next->_prev = newnode;newnode->_prev = prev;prev->_next = newnode;return pos;}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;return next;}void pop_back(){//erase(end()._node->_prev);erase(--end());}void pop_front(){erase(begin());}private:node* _phead;};

0
相关文章:
STL:List从0到1
🎉个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生 🙈个人主页🎉:GOTXX 🐼个人WeChat:ILXOXVJE 🐼本文由GOTXX原创,首发CSDN&…...
利用高分五号02星高光谱数据进行地物识别
高分五号02星搭载了一台60公里幅宽、330谱段、30米分辨率的可见短波红外高光谱相机(AHSI),可见近红外(400~1000nm)和短波红外光谱(1000~2500nm)分辨率分别达到5纳米和10纳米。单看参数性能优越&…...
前端如何识别上传的二维码---jsQR
npm npm i -d jsqrhtml <el-button click"$refs.input.click()">识别</el-button> <input type"file" style"display: none" id"input" input"upload">js import jsQR from "jsqr";decodeQR…...
flink1.18.0 自定义函数 接收row类型的参数
比如sql中某字段类型 array<row<f1 string,f2 string,f3 string,f4 bigint>> 现在需要编写 tableFunction 需要接受的参数如上 解决方案 用户定义函数|阿帕奇弗林克 --- User-defined Functions | Apache Flink...
JDK8和JDK11在Ubuntu18上切换(解决nvvp启动报错)
本文主要介绍JDK8和JDK11在Ubuntu18上切换,以供读者能够理解该技术的定义、原理、应用。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:计算机杂记 🎀CSDN主页 发狂的小花 🌄人…...
基于eleiment-plus的表格select控件
控件不是我写的,来源于scui,但在使用中遇到了一些问题,希望能把过程记录下来,同时把这个问题修复掉。 在使用的时候对控件进行二级封装,比如我的一个商品组件,再很多地方可以用到,于是 <template>&l…...
「❤️万文总结 时光回忆录❤️」那年,我在北京邮电大学计算机学院求学的日子
文章目录 关于我 | About Me梦绕西土城,邮情涌流 | Dreams and Connections in Haidian 北邮求学记 | My Days at BUPT岁月如歌,追忆往昔 | Reminiscing the Fleeting Years新篇章:班级与环境 | New Class, New Surroundings高压与挑战&#…...
【四 (1)数据可视化之如何选用正确的图表】
目录 文章导航一、数据分析中可视化的作用1、揭示数据关联和模式2、支持数据分析和决策3、提升沟通和共享效果4、强调关键信息和发现5、增强故事叙述和记忆效果6、有效增强数据交互性数据7、复杂信息易理解8、数据多维度显示 二、如何选用合适的图表1、简洁性避免使用过于复杂或…...
PHP<=7.4.21 Development Server源码泄露漏洞 例题
打开题目 dirsearch扫描发现存在shell.php 非预期解 访问shell.php,往下翻直接就看到了flag.. 正常解法 访问shell.php 看见php的版本是7.3.33 我们知道 PHP<7.4.21时通过php -S开起的WEB服务器存在源码泄露漏洞,可以将PHP文件作为静态文件直接输…...
大语言模型RAG-技术概览 (一)
大语言模型RAG-技术概览 (一) 一 RAG概览 检索增强生成(Retrieval-AugmentedGeneration, RAG)。即大模型在回答问题或生成问题时会先从大量的文档中检索相关的信息,然后基于这些信息进行回答。RAG很好的弥补了传统搜索方法和大模型两类技术…...
【嵌入式DIY实例】-DIY锂电池电压检测表
DIY锂电池电压检测表 文章目录 DIY锂电池电压检测表1、直流电压检测传感器介绍2、硬件准备3、代码实现4、OLED显示在电子应用中,通常需要使用到电池,电源管理是必不可少的部分。本文将详细介绍如何使用一个0-25V的直流电压传感器来检测锂电池的电压。 1、直流电压检测传感器介…...
生成baidu.com域名的私有证书:Linux系统命令示例
在Linux系统上生成一个针对xzyxdev.prec-tech.com域名的私有证书(通常指的是自签名证书),你可以使用openssl工具。以下是一个简单的步骤和命令示例来生成这样的证书: 生成私钥 首先,你需要生成一个私钥。这通常是一个…...
小程序学习4 mock
services/home.js import { config, cdnBase } from ../../config/index;/** 获取首页数据 */ function mockFetchHome() {const { delay } require(../_utils/delay);const { genSwiperImageList } require(../../model/swiper);return delay().then(() > {return {swip…...
Unity3D MMORPG角色的UI血条管理详解
前言 在Unity3D游戏开发中,MMORPG(Massively Multiplayer Online Role-Playing Game)游戏是一种非常流行的游戏类型。在这种类型的游戏中,玩家通常可以选择不同的角色来进行游戏,而角色的血条管理是游戏中非常重要的一…...
【python】爬取杭州市二手房销售数据做数据分析【附源码】
一、背景 在数据分析和市场调研中,获取房地产数据是至关重要的一环。本文介绍了如何利用 Python 中的 requests、lxml 库以及 pandas 库,结合 XPath 解析网页信息,实现对链家网二手房销售数据的爬取,并将数据导出为 Excel 文件的过…...
Day34:安全开发-JavaEE应用反射机制攻击链类对象成员变量方法构造方法
目录 Java-反射-Class对象类获取 Java-反射-Field成员变量类获取 Java-反射-Method成员方法类获取 Java-反射-Constructor构造方法类获取 Java-反射-不安全命令执行&反序列化链构造 思维导图 Java知识点 功能:数据库操作,文件操作,…...
Transformer代码从零解读【Pytorch官方版本】
文章目录 1、Transformer大致有3大应用2、Transformer的整体结构图3、如何处理batch-size句子长度不一致问题4、MultiHeadAttention(多头注意力机制)5、前馈神经网络6、Encoder中的输入masked7、完整代码补充知识: 1、Transformer大致有3大应…...
安卓性能优化面试题 31-35
31. 简述Handler导致的内存泄露的原因以及如何解决 ?在Android开发中,Handler对象可能导致内存泄漏的主要原因是由于Handler持有对外部类对象的隐式引用,从而导致外部类无法被垃圾回收,进而引发内存泄漏。下面是导致Handler内存泄漏的几种常见情况及相应的解决方法: 1. 长…...
QML与C++通信
一、QML中如何使用C的类和对象 前提条件: 1.从 QObject 或 QObject 的派生类继承 2.使用 Q_OBJECT 宏 这两个条件是为了让一个类能够进入 Qt 强大的元对象系统(meta-object system)中,只有使用元对象系统,一个类的某些…...
Explain详解与索引优化最佳实践
Explain工具介绍 使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈 在select语句之前增加explain关键字,MySQL会在查询前设置一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL 注意: 如果from中包含子查询,仍会执行该子查询,将结果…...
SpringBoot+Vue IT交流和分享平台平台完整项目源码+SQL脚本+接口文档【Java Web毕设】
系统架构设计### 摘要 随着信息技术的快速发展,互联网已成为人们获取和分享知识的重要渠道。尤其是在IT领域,技术人员和爱好者需要一个高效、便捷的交流平台来分享经验、讨论技术问题并获取最新行业动态。传统的论坛和社交媒体平台虽然功能丰富ÿ…...
GME-Qwen2-VL-2B效果实测:LaTeX公式截图转代码的准确率与效率
GME-Qwen2-VL-2B效果实测:LaTeX公式截图转代码的准确率与效率 如果你经常需要处理学术论文或者技术文档,肯定遇到过这样的麻烦事:看到一篇PDF或者网页上有个特别复杂的数学公式,想在自己的文档里用,结果发现要么没提供…...
SEO推广系统与其他推广渠道的对比
SEO推广系统与其他推广渠道的对比 在现代商业环境中,各种推广渠道层出不穷,其中SEO推广系统和其他传统或新兴的推广渠道各有优劣。本文将从问题分析、原因说明、解决方法、注意事项和实用建议五个方面,深入探讨SEO推广系统与其他推广渠道的对…...
开源CLAP音频分类实战案例:上传MP3/WAV即得语义标签
开源CLAP音频分类实战案例:上传MP3/WAV即得语义标签 1. 项目概述 今天给大家介绍一个特别实用的AI工具——CLAP音频分类服务。这是一个基于LAION CLAP模型的开源项目,能够让你上传任何音频文件,就能自动识别出里面的内容是什么。 简单来说…...
微前端进阶:WuJie + Vite + Vue3 的无界架构性能优化全攻略
1. WuJie微前端框架的核心优势 WuJie作为新一代微前端解决方案,最大的特点就是真正实现了"无界"体验。我在多个大型项目中实测发现,它完美解决了传统iframe方案存在的样式隔离、通信困难等问题。不同于single-spa这类基于路由的微前端框架&…...
gui 的高清与标清
现在无论对图层设计多样化 一般采用4层 或者更多:/*** file display_config.h* brief 显示配置头文件 - 定义图层管理和显示参数* details 采用4层图层设计,支持高清/标清自适应*/ #ifndef DISPLAY_CONFIG_H #define DISPLAY_CONFIG_H #include &l…...
第 6 次执行后,PostgreSQL 执行计划为何突变?
引言 在 PostgreSQL 中,预处理语句通常用于提升性能并防止 SQL 注入。但一个不易察觉的行为是:查询规划器会在执行达到特定次数后自动改变执行计划。 这种变化往往令人困惑——SQL 本身未发生变化,执行计划却突然发生切换,有时甚至…...
深入解析pysim中的eUICC ISD-R命令:从基础操作到高级应用
1. eUICC ISD-R命令基础入门 第一次接触eUICC ISD-R命令时,我完全被那些专业术语搞晕了。经过几个项目的实战,我发现这些命令其实就像智能手机上的应用商店操作——只不过管理的是SIM卡上的应用。eUICC(嵌入式通用集成电路卡)是现…...
无失效数据的产品可靠性评估案例
当所有寿命相关的试验全部通过且无失效发生时如何评价产品可靠性作者:Julius王政 关键点o 一个产品可能有几项与寿命相关的可靠性验证试验。例如,车辆中使用的电子控制模块(我们称之为 ECU)通常有以下四项与寿命相关的试…...
2026 靠谱网站建设公司推荐|中大型企业 / 上市公司建站避坑与优选指南
摘要 在 AI 与 GEO(生成式引擎优化)主导的 2026 年,企业官网早已不是简单的展示窗口,而是品牌信任、获客转化、合规披露、全球触达的核心数字资产。选择一家靠谱的网站建设公司,直接决定企业数字化成果与长期商业价值。…...
