C++ ─── List的模拟实现
目录
编辑
一, List的模拟实现
二,代码实现
三、list和vector的区别
一, List的模拟实现
List 是一个双向循环链表,由于List的节点不连续,不能用节点指针直接作为迭代器,因此我们要对结点指针封装,来实现迭代器的作用。
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
1. 原生态指针,比如:vector
2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1. 指针可以解引用,迭代器的类中必须重载operator*()
2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前 移动,所以需要重载,如果是forward_list就不需要重载--
4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
二,代码实现
#pragma once
#include<assert.h>
#include<iostream>
#include <initializer_list>
#include<algorithm>
using namespace std;namespace BMH
{template<class T>struct ListNode{typedef ListNode<T> Node;Node* _prev;Node* _next;T _data;ListNode(const T& data = T()):_prev(nullptr), _next(nullptr), _data(data){}};template<class T, class Ref, class Ptr>struct ListIterator{//正向迭代器typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到public:typedef Ref Ref;typedef Ptr Ptr;Node* _node;ListIterator(Node* node =nullptr):_node(node){}//++itSelf& operator++(){_node = _node->_next;return *this;//++it 返回自己(迭代器)}//--itSelf& operator--(){_node = _node->_prev;return *this;}//it++Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}//it--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}//// 具有指针类似行为//*it 返回值Ref operator*(){return _node->_data;;}//it-> 返回指针Ptr operator->(){return &(_node->_data);}////// 迭代器支持比较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;/////初始化创建头结点void empty_init(){_head = new Node();_head->_prev = _head;_head->_next = _head;}//构造函数List(){empty_init();}List(int n, const T& value = T()){empty_init();for (int i = 0; i < n; ++i)push_back(value);}//用下面拷贝构造函数来实现构造函数,拷贝构造函数是构造函数的一种。//List<int> lt2(lt1)//List(const List<T>& lt)//{// empty_init();// for (const auto& e : lt)// {// Push_Back(e);// }//}//List<int> lt1 ={1,2,3,4}List(initializer_list<T> il)//不用引用的原因:il本身是两个指针,拷贝代价小{empty_init();for (const auto& e : il){Push_Back(e);}}template<class Inputiterator >List(Inputiterator p1, Inputiterator p2){empty_init();while (p1 != p2){Push_Back(*p1);++p1;}}//拷贝构造//lt2(lt1)List(const List<T>& lt){empty_init();for (const auto& e : lt){Push_Back(e);}}//赋值重载//lt1=lt2List<T>& operator=(List<T> lt){swap(_head, lt._head);return *this;}void clear(){iterator it = begin();while (it != end()){it = erase(it);//用erase时会发生迭代器失效}}~List(){clear();delete _head;_head = nullptr;}/////迭代器iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}///// 容量相关//尾插void Push_Back(const T& x){Node* tail = _head->_prev;Node* newnode = new Node(x);newnode->_prev = tail;tail->_next = newnode;newnode->_next = _head;_head->_prev = newnode;}void Pop_Back(){erase(--end());}void Push_Front(const T& x){insert(begin(),x);}void Pop_Front(){erase(begin());}//之前插入,无迭代器失效iterator insert(iterator pos ,const T& data ){Node* cur = pos._node;//pos是迭代器,找到其中的节点地址即可Node* newnode = new Node(data);Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur-> _prev= newnode;return iterator(newnode);}//有迭代器失效,返回删除节点下一个的迭代器iterator erase(iterator pos){assert(pos!= (*this).end());//防止将Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;prev->_next = next;next->_prev = prev;delete cur;return iterator(next);}private:Node* _head;};
三、list和vector的区别
1、任意位置插入删除时:list可以随意插入删除,但是vector任意位置的插入删除效率低,需要挪动元素,尤其是插入时有时候需要异地扩容,就需要开辟新空间,拷贝元素,释放旧空间,效率很低
2、访问元素时:vector支持随机访问,但是list不支持随机访问
3、迭代器的使用上:vector可以使用原生指针,但是list需要对原生指针进行封装
4、空间利用上:vector使用的是一个连续的空间,空间利用率高,而list使用的是零碎的空间,空间利用率低

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助❤
欢迎各位点赞,收藏和关注哦❤
如果有疑问或有不同见解,欢迎在评论区留言哦❤
后续我会一直分享双一流211西北大学软工(C,数据结构,C++,Linux,MySQL)的学习干货以及重要代码的分享
相关文章:
C++ ─── List的模拟实现
目录 编辑 一, List的模拟实现 二,代码实现 三、list和vector的区别 一, List的模拟实现 List 是一个双向循环链表,由于List的节点不连续,不能用节点指针直接作为迭代器,因此我们要对结点指针封装,来…...
Spring Boot详解
好的!Spring Boot 是一个基于 Spring 框架的项目,它为简化配置、快速启动项目而生。它使得构建独立运行、生产级别的 Spring 应用变得非常简单,让开发者专注于业务逻辑而不再被繁琐的配置所困扰。接下来,我将从以下几个方面为你详…...
Proxfier+burpsuite抓包配置问题
1、burp证书配置 导出证书 后缀为cer 打开浏览器设置 搜索证书--》点安全 管理证书 在圈起来的三个地方添加证书 2、Proxifer配置 配置代理服务器 配置ip和port 配置代理规则 注意画圈部分...
sqli-lab靶场学习(一)——Less1-4
前言 最近一段时间想切入安全领域,因为本身有做数据库运维工作,就打算从sql注入方向切入。而sql注入除了学习日常书本上的概念外,需要有个实践的环境,刚好看到sqli-lab这个靶场,就打算先用这个来学习。 安装部署 网上…...
el-select如何同时获取value和label?
在element ui 中 下拉框默认获取下拉框value的值,但是有时候根据 业务需求,我们需要label值也发送给后端,在这提供一下获取value、和label 的方式 1、在给el-option绑定:value值时使用对象的方式,将value和label同时绑定到:value…...
1.初识ChatGPT:AI聊天机器人的革命(1/10)
引言 在当今的数字化世界中,人工智能(AI)正以其独特的方式重塑我们的生活和工作。其中,AI聊天机器人作为人机交互的前沿技术,已经成为企业与客户沟通、提供个性化服务的重要工具。这些机器人通过模拟人类的对话方式&a…...
API安全 | 发现API的5个小tips
在安全测试目标时,最有趣的测试部分是它的 API。API 是动态的,它们比应用程序的其他部分更新得更频繁,并且负责许多后端繁重的工作。在现代应用程序中,我们通常会看到 REST API,但也会看到其他形式,例如 Gr…...
数据结构---单向链表
单向链表 //链表的创建 Link_t *create_link() {Link_t *plink malloc(sizeof(Link_t));if(NULL plink){perror("fail plink");return NULL;}plink->phead NULL;plink->clen 0;return plink; } //头插 int push_link_head(Link_t *plink, DataType data…...
基于STM32设计的ECG+PPG人体参数测量系统(华为云IOT)(217)
文章目录 一、前言1.1 项目介绍【1】开发背景【2】项目实现的功能【3】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】整体构架【3】上位机开发思路【4】ESP8266工作模式配置1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】摘要【5】项目背景1.4 开发…...
SpringBoot教程(十五) | SpringBoot集成RabbitMq(死信队列、延迟队列)
SpringBoot教程(十五) | SpringBoot集成RabbitMq(死信队列、延迟队列) (一)死信队列使用场景具体用法前提示例: (二)延迟队列使用场景方法一:通过死亡队列实现方法二&…...
Dubbo依赖包
Dubbo 是一个高性能的 RPC 框架,用于构建分布式服务治理系统。要使用 Dubbo,项目中需要引入一些关键的依赖包。这些依赖包提供了 Dubbo 的核心功能、服务注册与发现、网络通信、序列化等能力。 一、Dubbo 核心依赖包 Dubbo 的核心依赖包包含了实现 RPC…...
webGIS后端程序员学习路线
webGIS后端程序员学习路线 1. GIS 基础知识 学习要点: 学习资源: 2. 后端编程基础 学习要点: 学习资源: 3. 地理数据库(Spatial Database) 学习要点: 学习资源: 4. 空间数…...
OpenCV绘图函数(15)图像上绘制矩形函数 rectangle()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 绘制一个简单的、粗的或填充的直立矩形。 这个函数 cv::rectangle 绘制一个矩形轮廓或一个填充的矩形,其两个相对的顶点分别是 pt1 和…...
从零开始,认识游戏设计师(4)体验源于设计师②
认真并仔细地揣摩你的想法 了解自己的感受并不是一件简单的事情,作为设计师,我觉得比了解玩家总体感觉的技能更重要的是你能清楚知道描述自己感受。 试想一下,你是否能准确描述你喜欢什么,你讨厌什么,以及为什么这样…...
周末总结(2024/09/07)
工作 人际关系核心实践: 要学会随时回应别人的善意,执行时间控制在5分钟以内 坚持每天早会打招呼 遇到接不住的话题时拉低自己,抬高别人(无阴阳气息) 朋友圈点赞控制在5min以内,职场社交不要放在5min以外 职场的人际关系在面对利…...
MySQL数据库的SQL注入漏洞解析
说明:本文仅是用于学习分析自己搭建的SQL漏洞内容和原理,请勿用在非法途径上,违者后果自负,与笔者无关;本文开始前请认真详细学习《中华人民共和国网络安全法》及其相关法规内容【学法时习之丨网络安全在身边一图了解网络安全法_中央网络安全和信息化委员会办公室】 …...
Redis进阶(七):分布式锁
在分布式系统下,涉及到多个节点访问同一个公共资源的情况,此时需要通过 锁 进行互斥控制:避免出现 线程安全问题。 1.分布式锁的基本实现 超卖问题: 解决: 采用redis实现分布式锁 可用采取:在购票的时候࿰…...
Python 中考虑 concurrent.futures 实现真正的并行计算
Python 中考虑 concurrent.futures 实现真正的并行计算 思考,如何将代码所要执行的计算任务划分成多个独立的部分并在各自的核心上面平行地运行。 Python 的全局解释器锁(global interpreter lock,GIL)导致没办法用线程来实现真…...
【C++多线程编程】 线程安全与对象生命周期管理
目录 类的线程安全 实现线程安全 构造函数在多线程中的安全性 析构函数多线程环境的安全 智能指针实现多线程安全 shared_ptr 非完全线程安全 shared_ptr可能导致对象生命周期延长 const引用可以减少传递shared_ptr开销 shared_ptr 智能指针块模块的优点 析构所在线程…...
【系统架构设计师-2024年-上半年】综合知识-答案及详解
更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16~17题】【第18~19题】【第20~21题】【第22题】【第23题】…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学
一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件,其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时,价带电子受激发跃迁至导带,形成电子-空穴对,导致材料电导率显著提升。…...
【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验
2024年初,人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目(一款融合大型语言模型能力的云端AI编程IDE)时,技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力,TRAE在WayToAGI等…...

