C++:list模拟实现
hello,各位小伙伴,本篇文章跟大家一起学习《C++:list模拟实现》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !
如果本篇文章对你有帮助,还请各位点点赞!!!

话不多说,开始进入正题
🍁list的逻辑结构以及节点代码

是一个双指针带头链表,所以我选择用一个结构体ListNode来维护节点,如下:
// List的节点类
template<class T>
struct ListNode
{ListNode(const T& val = T()):_val(val),_pPre(nullptr),_pNext(nullptr){}ListNode<T>* _pPre;// 指向前一个结点ListNode<T>* _pNext;// 指向后一个节点T _val;// 该结点的值
};
我对ListNode<T>改一个名字:Node:
typedef ListNode<T> Node;
typedef Node* PNode;
🍁list类
🍃私有成员变量_pHead和私有成员函数CreateHead()
private:void CreateHead()// 创建头节点并且初始化{_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;}PNode _pHead;
🍃尾插函数和插入函数
尾插只是插入的其中一种方式,所以实现了插入函数,就能够实现尾插函数。
插入思路图解:在pos位置前插入值为val的节点
创建新节点值为value后;
使prev节点的_pNext指针指向newnode,newnode的节点的_pPre指向prev;
使cur节点的_pPre指针指向newnode,newnode的节点的_pNext指向cur;
最后返回iterator(newnode);

itearator为迭代器,后面会实现
- 插入
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{Node* cur = pos._pNode;Node* newnode = new Node(val);Node* prev = cur->_pPre;// prev newnode curprev->_pNext = newnode;newnode->_pPre = prev;newnode->_pNext = cur;cur->_pPre = newnode;return iterator(newnode);
}
- 尾插
void push_back(const T& val)
{insert(end(), val);
}
🍃构造函数
- 无参构造
list(const PNode& pHead = nullptr)
{CreateHead();/*_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/
}
- 带参构造(数值)
list(int n, const T& value = T())
{CreateHead();for (int i = 0; i < n; ++i)push_back(value);
}
- 带参构造(迭代器)
template <class Iterator>
list(Iterator first, Iterator last)
{CreateHead();while (first != last){push_back(*first);++first;}
}
- 拷贝构造
list(const list<T>& l)
{CreateHead();// 复用带参构造(迭代器)list<T> temp(l.cbegin(), l.cend());// 与*this的头节点pHead交换指向swap(temp);
}
🍃析构函数
clear()为其中的成员函数,功能:清理list中的数据
~list()
{clear();delete _pHead;_pHead = nullptr;/*Node* cur = _pHead->_pNext;Node* tmp = cur->_pNext;while (cur != _pHead){delete cur;cur = tmp;tmp = tmp->_pNext;}tmp = cur = nullptr;_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/
}
🍃迭代器模拟
逻辑上并不难,也许难理解于模板
//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*(){assert(_pNode != _pNode->_pNext);return _pNode->_val;}T* operator->(){return &(*this);}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){PNode* tmp = _pNode;_pNode = _pNode->_pNext;return tmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){PNode* tmp = _pNode;_pNode = _pNode->_pPre;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}PNode _pNode;
};
这段代码定义了一个模板结构 ListIterator,用于表示List类的迭代器。让我们来解释模板声明部分:
template<class T, class Ref, class Ptr>;
这一行是模板声明,定义了一个模板类 ListIterator,它有三个模板参数:T、Ref 和 Ptr。让我们逐个解释这些参数的作用:
1.T: 这是一个模板参数,表示迭代器指向的元素类型。在使用 ListIterator 时,你需要提供实际的类型作为 T 的值。
2.Ref: 这也是一个模板参数,表示迭代器的引用类型。通常情况下,当你通过迭代器解引用(使用 * 运算符)时,你希望得到的是元素的引用类型。所以 Ref 通常被设定为 T&,表示引用类型为 T 的元素。
3.Ptr: 这是迭代器的指针类型。与 Ref 类似,当你通过迭代器解引用(使用 -> 运算符)时,你希望得到的是元素的指针类型。因此,通常情况下 Ptr 被设定为 T*,表示指针类型为 T 的元素。
通过将这些参数设定为模板参数,ListIterator 类可以适用于不同类型的元素,同时也可以提供不同的引用和指针类型。这样做使得 ListIterator 类更加灵活,能够适用于不同的使用场景。
- 封装的意义
将迭代器的实现从 List 类中分离出来,有几个重要的意义和优势:
- 模块化设计:通过将迭代器封装为单独的类,可以实现更模块化的设计。这意味着 List 类的实现与迭代器的实现可以分开,每个类都专注于自己的职责。这样的设计使得代码更易于理解、维护和测试。
- 可重用性:通过将迭代器设计为独立的类,可以在不同的容器类中重复使用相同的迭代器实现。例如,如果你有另一个类似于 List 的容器类,也需要迭代器来遍历其中的元素,你可以直接重用相同的迭代器实现,而无需重新编写。
- 灵活性:将迭代器设计为独立的类使得它们的实现更加灵活。你可以在迭代器类中添加额外的功能或改变迭代器的行为,而不会影响到容器类的实现。这样的设计使得容器和迭代器的职责分离,每个类可以独立地演化和改进。
- 通用性:独立的迭代器类可以设计成通用的,适用于多种容器类型。这意味着你可以为不同的容器类实现相同的迭代器接口,使得用户在使用不同的容器时无需学习不同的迭代器接口,提高了代码的一致性和可用性。
总的来说,将迭代器封装为独立的类使得代码更加模块化、可重用、灵活和通用,提高了代码的可维护性、可扩展性和可读性。
🍃list类中迭代器的使用
public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;
- begin()和end()
// List Iterator
iterator begin()
{return _pHead->_pNext;
}iterator end()
{return _pHead;
}const_iterator begin() const
{return _pHead->_pNext;
}const_iterator end() const
{return _pHead;
}
- erase
删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{assert(pos._pNode != _pHead);Node* Prev = pos._pNode->_pPre;Node* Next = pos._pNode->_pNext;delete pos._pNode;Prev->_pNext = Next;Next->_pPre = Prev;return iterator(Next);
}
🍃List Modify
void push_back(const T& val) { insert(end(), val); }
void pop_back() { erase(--end()); }
void push_front(const T& val)
{ assert(!empty());insert(begin(), val);
}
void pop_front() { erase(begin()); }
🍁全部代码
#pragma once
#include<assert.h>
#include<iostream>
using namespace std;namespace My_List
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_val(val),_pPre(nullptr),_pNext(nullptr){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//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*(){assert(_pNode != _pNode->_pNext);return _pNode->_val;}T* operator->(){return &(*this);}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){PNode* tmp = _pNode;_pNode = _pNode->_pNext;return tmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){PNode* tmp = _pNode;_pNode = _pNode->_pPre;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}PNode _pNode;};//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(const PNode& pHead = nullptr){CreateHead();/*_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/}list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i)push_back(value);/*int cnt = 0;while (cnt < n){PNode _first = new Node(value);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++cnt;}*/}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}/*while (first != last){PNode _first = new Node(*first);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++first;}*/}list(const list<T>& l){CreateHead();list<T> temp(l.cbegin(), l.cend());swap(temp);/*iterator first = l._pHead->_pNext;iterator last = l._pHead;while (first != last){PNode _first = new Node(*first);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++first;}*/}list<T>& operator=(const list<T> l){CreateHead();swap(l);return *this;/*iterator first = l._pHead->_pNext;iterator last = l._pHead;while (first != last){PNode _first = new Node(*first);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++first;}return *this;*/}~list(){clear();delete _pHead;_pHead = nullptr;/*Node* cur = _pHead->_pNext;Node* tmp = cur->_pNext;while (cur != _pHead){delete cur;cur = tmp;tmp = tmp->_pNext;}tmp = cur = nullptr;_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/}///// 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{Node* cur = _pHead->_pNext;size_t cnt = 0;while (cur != _pHead){++cnt;cur = cur->_pNext;}return cnt;}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) { assert(!empty());insert(begin(), val); }void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* cur = pos._pNode;Node* newnode = new Node(val);Node* prev = cur->_pPre;// prev newnode curprev->_pNext = newnode;newnode->_pPre = prev;newnode->_pNext = cur;cur->_pPre = newnode;return iterator(newnode);}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(pos._pNode != _pHead);Node* Prev = pos._pNode->_pPre;Node* Next = pos._pNode->_pNext;delete pos._pNode;Prev->_pNext = Next;Next->_pPre = Prev;return iterator(Next);}void clear(){iterator cur = begin();while (cur != end()){cur = erase(cur);}_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;}void swap(list<T>& l){/*list<T> tmp = l;l = *this;*this = tmp;*/PNode tmp = _pHead;_pHead = l._pHead;l._pHead = tmp;}private:void CreateHead(){_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;}PNode _pHead;};
};
你学会了吗?
好啦,本章对于《C++:list模拟实现》的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!
如你喜欢,点点赞就是对我的支持,感谢感谢!!!

相关文章:
C++:list模拟实现
hello,各位小伙伴,本篇文章跟大家一起学习《C:list模拟实现》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 如果本篇文章对你有帮助,还请各位点点赞!…...
植物大战僵尸杂交版全平台 PC MAC 安卓手机下载安装详细图文教程
最近植物大战僵尸杂交版非常的火,好多小伙伴都想玩一玩,但作者只分享了 win 版,像手机还有MAC电脑都没有办法安装,身为 MAC 党当然不能放弃,经过一番折腾,也是成功在所有平台包括手机和MAC电脑都成功安装上…...
发送Http请求的两种方式
说明:在项目中,我们有时会需要调用第三方接口,获取调用结果,来实现自己的业务逻辑。调用第三方接口,通常是双方确定好,由对方开放一个接口,需要我们根据他们提供的接口文档,组装Http…...
【算法训练记录——Day23】
Day23——二叉树Ⅸ 669.修剪二叉搜索树108.将有序数组转换为二叉搜索树538.把二叉搜索树转换为累加树 今日内容: ● 669.修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 ● 总结篇 669.修剪二叉搜索树 思路:主要是…...
【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示
📝个人主页:哈__ 期待您的关注 目录 一、🔥今日内容 二、🌏前端页面的改造 2.1新增电子书管理页面 2.2新增路由规则 2.3修改the-header代码 三、🚗SpringBoot后端Ebook模块改造 3.1增加电子书增/改接口 3.1.…...
NTLM Relay Gat:自动化NTLM中继安全检测工具
关于NTLM Relay Gat NTLM Relay Gat是一款功能强大的NTLM中继威胁检测工具,该工具旨在利用Impacket工具套件中的ntlmrelayx.py脚本在目标环境中实现NTLM中继攻击风险检测,以帮助研究人员确定目标环境是否能够抵御NTLM中继攻击。 功能介绍 1、多线程支持…...
摸鱼大数据——Hive函数14
14、开窗(开列)函数 官网链接:Window Functions - Apache AsterixDB - Apache Software Foundation 14.1 基础使用 开窗函数格式: 开窗函数 over(partition by 分组字段名 [order by 排序字段名 asc|desc] [rows between 开窗开始 and 开窗结束]) partition b…...
elasticsearch的常规操作--增删改查和批量处理
1、_cat 查询 GET /_cat/nodes: 查看所有节点 GET /_cat/health: 查看es 健康状况 GET /_cat/master: 查看主节点 GET /_cat/indices:查看所有索引show databases; 2、索引一个文档(保存) 保存一个数据&…...
盘点2024年还在活跃发版的开源私有网盘项目附源码链接
时不时的会有客户上门咨询,丰盘ECM是不是开源项目,源码在哪里可以下载;如果需要和内部其他系统做集成,购买商业版的话,能否提供源代码做二次开发呢,等等诸多问题。 这里做个统一回复,丰盘ECM产…...
MySQL 使用方法以及教程
一、引言 MySQL是一个流行的开源关系型数据库管理系统(RDBMS),广泛应用于Web开发、数据分析等领域。它提供了高效、稳定的数据存储和查询功能。同时,Python作为一种强大的编程语言,也提供了多种与MySQL交互的库&#…...
算法学习笔记——二进制
二进制 负数的十进制转二进制数(-2 -> 1110): 正数 - 1,再取反,得到负数的二进制。 例如:-2 :0010 -> 0010 - 1 -> 0001 -> 取反 -> 1110 负数的二进制转十进制(…...
计算机网络介绍
计算机网络介绍 概述网络概述相关硬件 链路层VLAN概念VLAN 特点VLAN 的划分帧格式端口类型原理 STP概念特点原理 Smart Link概念特点组网 网络层ARP概念原理 IP概念版本IP 地址 IPv4IP 地址数据报格式 IPv6特点IP 地址数据报格式 ICMP概念分类报文格式 VRRP概念原理报文格式 OS…...
解锁数据宝藏:高效查找算法揭秘
代码下载链接:https://gitee.com/flying-wolf-loves-learning/data-structure.git 目录 一、查找的原理 1.1 查找概念 1.2 查找方法 1.3平均查找长度 1.4顺序表的查找 1.5 顺序表的查找算法及分析 1.6 折半查找算法及分析 1.7 分块查找算法及分析 1.8 总结…...
利用EasyCVR视频智能监控技术,构建智慧化考场监管体系
随着科技的进步,视频监控在各个领域的应用越来越广泛,其中在考场中的应用尤为显著。视频监控不仅能够提高考场的监管水平,确保考试的公平、公正和公开,还能有效预防和打击作弊行为,为考生营造一个良好的考试环境。 传…...
深度解析:速卖通618风控下自养号测评的技术要点
速卖通每年的618大促活动平台的风控都会做升级,那相对的测评技术也需要进行相应的做升级,速卖通618风控升级后,自养号测评需要注意以下技术问题,以确保测评 的稳定性和安全性: 一、物理环境 1. 硬件参数伪装&#x…...
国产算力——沐曦GPU性能及应用
沐曦集成电路(上海)有限公司(简称“沐曦”)成立于2020年9月,专注于为异构计算提供全栈GPU芯片及解决方案,满足数据中心对“高性能”、“高能效”及“高通用性”的算力需求。 产品系列 沐曦构建了全栈高性…...
贪心算法拓展(反悔贪心)
相信大家对贪心算法已经见怪不怪了,但是一旦我们的决策条件会随着我们的步骤变化,我们该怎么办呢?有没有什么方法可以反悔呢? 今天就来讲可以后悔的贪心算法,反悔贪心。 https://www.luogu.com.cn/problem/CF865Dhttp…...
在spring框架的基础上自定义autowired注解
在Spring框架的基础上自定义Autowired注解是不可能的,因为注解本身是Java语言的一部分,并且Autowired是Spring框架提供的注解,用于实现自动装配。但是,你可以创建自己的注解,并结合Spring框架的扩展机制来实现类似的功…...
2005NOIP普及组真题 3. 采药
线上OJ: [05NOIP普及组] 采药 核心思想: 1、题与 2006 年普及组第2题《开心的金明》一样,考察的都是01背包。 2、直接套用01背包的一阶模板即可 a、限定时间看成背包总容量m b、每件物品的采药时间 v 看成占用背包的体积 c、每件物品的价格w作为该物品的…...
preventDefault()与stopPropagation()有什么区别?
1、event.preventDefault()方法 (1)可防止元素的默认行为 (2)如果在表单元素中使用,它将阻止其提交 (3)如果在锚元素中使用,它将阻止其导航 (4)如果在上下…...
UMI 采集技术落地应用 核数聚助力人形机器人快速迭代
在具身智能从实验室走向产业落地的关键期,数据饥渴已成为行业公认的核心瓶颈。传统真机遥操作采集成本高、效率低、泛化性差,仿真数据又存在物理真实性不足的问题。此时,UMI(Universal Manipulation Interface,通用操作…...
VSCode Mermaid Preview:面向技术团队的实时图表协作解决方案
VSCode Mermaid Preview:面向技术团队的实时图表协作解决方案 【免费下载链接】vscode-mermaid-preview Previews Mermaid diagrams 项目地址: https://gitcode.com/gh_mirrors/vs/vscode-mermaid-preview 在技术文档编写、系统架构设计和项目规划过程中&…...
好书推荐《VirtualLab Fusion入门与进阶实用教程(第二版)》
目 录第一章 VirtualLab Fusion理论基础 1 1.1 几何光学和光线追迹 1 1.2 物理光学和光场追迹 1 1.2.1 统一场追迹 3 1.2.2 第二代场追迹 6 第二章 VirtualLab Fusion安装与更新 10 2.1 VirtualLab 版本说明及系统配置要求 10 2.2 VirtualLab安装与更新 11 2.3 安装过程中可能遇…...
多版面文章活动公众号管理系统
文章营销活动系统概述基于微擎系统开发的在线交付文章营销推广类源码应用,支持多活动管理、多站点搭建及多版面切换。核心功能包括转发奖励积分或余额,适配文章推广、流量裂变及营销获客需求。核心功能多活动管理 后台可创建并管理多个营销活动ÿ…...
别再只画区间了!用ECharts的markArea实现单点高亮标注(附完整代码)
突破ECharts标记边界:用markArea实现单点高亮的高级技巧 在数据可视化领域,ECharts凭借其强大的功能和灵活的配置选项,已成为前端开发者和数据分析师的首选工具之一。当我们面对需要突出显示特定数据点的场景时,常规做法是使用mar…...
车标识别平台
车标识别平台选题背景分析随着全球汽车产业的蓬勃发展以及智能交通系统(ITS)的加速建设,车标识别技术作为计算机视觉与人工智能领域的重要应用分支,其市场需求与技术价值日益凸显。开发一个高效、精准的车标识别平台,其…...
现货TJA1101AHN/0Z是NXP推出的一款高性能、低功耗的汽车以太网PHY芯片,作为TJA1101A的改进版本,专为车载电子系统设计,支持100BASE-T1标准,具备出色的可靠性与集成度
TJA1101AHN/0Z 是NXP(恩智浦)推出的一款高性能、低功耗的汽车以太网PHY芯片,作为TJA1101A的改进版本,专为车载电子系统设计,支持100BASE-T1标准,具备出色的可靠性与集成度。核心性能与优势:…...
Java WebSocket六种集成方案详解:从JSR 356到Spring生态实战
1. 项目概述最近在折腾一个基于 Spring Cloud 的 WebSocket 集群方案时,我不得不把 Java 生态里那些五花八门的 WebSocket 集成方式都翻了个底朝天。不研究不知道,一个看似简单的 WebSocket,在 Java 世界里竟然有这么多“门派”,从…...
别再说国产模型不行了!DeepSeek V4 + Claude Code,编程体验直接起飞
别再说国产模型不行了!DeepSeek V4 Claude Code,编程体验直接起飞 还在觉得 DeepSeek V4 不如国外模型? 醒醒,2026 年了。DeepSeek V4 系列在代码能力上已经卷到让人窒息——而且价格只有 Claude 官方的零头。 但问题来了&…...
别再死循环了!手把手教你用Python实现D*算法(附完整代码与避坑指南)
从理论到实践:Python实现D*算法的工程化指南与避坑策略 路径规划中的动态适应挑战 在机器人导航和游戏AI开发中,路径规划算法扮演着至关重要的角色。传统算法如A*和Dijkstra虽然能有效解决静态环境下的路径规划问题,但在动态变化的环境中却显…...
