List中的迭代器实现【C++】
List中的迭代器实现【C++】
- 一. list的结构
- 二. 迭代器的区别
- 三. 迭代器的实现
- i. 类的设计
- ii. ++重载
- iii. !=重载
- iiii. begin()
- iiiii. end()
- iiiii. operator*
- 四.测试
- 五. const迭代器的实现
- i. 实现
- ii 优化实现
- 六. 整体代码
一. list的结构
其实按照习惯来说,应该要专门出一篇博客来写
list的模拟实现,但是其实list与vector以及string的主要区别在于迭代器的设计。
所以就偷个懒直接写迭代器的部分了。
这里先声明以下,我这里就是进行一下模拟实现,STL中的list的iterator虽然并不是这样实现的,但是实现逻辑和结构都大差不差
这里就先贴上list类的结构:
namespace list
{template<class T>struct list_node{list_node<T>* _prev;list_node<T>* _next;T _val;//节点的构造函数list_node(const T& val = T()):_prev(nullptr), _next(nullptr), _val(val){}};template<class T>class list{public:list(){//链表的默认构造list_node<T>* head = new list_node<T>;//初始化哨兵位_head = head;_head->_next = _head;_head->_prev = _head;_size = 0;}~list(){}private:list_node<T>* _head;};
}
这个其实和我们之前写的双向带头循环链表一样。
二. 迭代器的区别
迭代器的区别,落到实质问题上
还是容器与容器的区别,也就是vector与list的区别
vector中的iterator是这样去实现的。
首先:
typedef T* iterator;
这里先重命名
iterator begin(){return _start;}iterator end(){return _finish;}
随后直接设计end与begin的函数。
之后就能发现,范围for与迭代器能直接进行使用了。
因为我们实现vector指针的方法是直接将内置类型指针进行改名。
而内置类型指针支持++,所以可以直接运行程序了。
但我们想想list肯定就不支持这样的操作了
vector能这这样,是因为数据存储在内存空间中连续时,正好可以进行使用。
但是list的问题是,内存空间是不连续的
这样的话再用指针内部支持的++算法就不太合适了。
所以我们今天就是为了来模拟实现list的迭代器的实现。
首先的目标就是实现下面这个代码的跑动。
list::list<int>::iterator it = l1.begin();while (it != l1.end()){std::cout << *it;++it;}
三. 迭代器的实现
我们首先来看,我们最难解决的问题就是it的前置++
因为vector和list最重要的问题就是运算的方式不一样。
那我们想要用我们自己的方式进行++。
这个时候就应该想到了我们模拟实现类的时候最常用的东西:重载运算符
重载运算符在哪里能用:自定义类型
所以我们这个时候应该自然而然的想到自己写一个类,来充当iterator
从而实现我们想要的++方式。
i. 类的设计
template<class T>struct __list_iterator{list_node<T>* _node;__list_iterator(list_node<T>* node):_node(node){}};
基本上大致结构是这样。
其中list_node就是双链表的节点结构。(上面写过)
这里添加个typedef
template<class T>class list{public:typedef __list_iterator<T> iterator;
这个typedef和vefctor的使用没有什么大区别了。
现在来专注实现上面代码的所有的重载即可
ii. ++重载
__list_iterator<T>& operator++(){_node = _node->_next;return *this;}
这个就是我们以前写的双链表和单链表的部分了。
iii. !=重载
bool operator!=(const __list_iterator<T>& node){return _node != node._node;}
iiii. begin()
注意:这里的end和begin都是在list中的
因为迭代器执行时,会在list中寻找begin和end
iterator begin(){return iterator(_head->_next);}
这里我们需要返回的是迭代器的类型
所以需要调用一下迭代器的构造函数
iiiii. end()
iterator end(){return _head;}
我们发现begin需要调用构造函数
但是这边end却没有调用
因为单参数的构造函数返回时
如果返回的类型和需要返回的类型不同
就会主动调用需要返回类型的构造函数进行转换
iiiii. operator*
T& operator*(){return _node->_val;}
四.测试
这里就直接写一个push_back的方法
void push_back(const T& val){insert(end(), val);}void insert(iterator pos, const T& val){list_node<T>* new_node = new list_node<T>(val);_size++;pos._node->_prev->_next = new_node;new_node->_prev = pos._node->_prev;new_node->_next = pos._node;pos._node->_prev = new_node;}
接下来进行测试即可
list::list<int> l1;l1.push_back(1);l1.push_back(1);l1.push_back(1);l1.push_back(1);l1.push_back(1);list::list<int>::iterator it = l1.begin();while (it != l1.end()){std::cout << *it;++it;}

这里能发现程序完美执行了。
五. const迭代器的实现
我们在使用STL中自带的迭代器时
应该经常能用到const迭代器。
const_iterator
这里我们首先要清楚const_iterator实现的是什么:
我们清楚效果是:指向的内容不能修改,但是迭代器本身可以修改。
所以实现的类型就是const T* ptr
而不是T* const ptr
那我们要达成这种效果。
可以从函数的返回值上入手
平常使用函数时,基本上都是通过重载符*
来进行对应值的修改
const T& operator*(){return _node->_val;}
那我们这样不就可以了吗。。
i. 实现
typedef __list_iterator<T>const_iterator;
这里在list中重命名一下。
template<class T>struct __list_const_iterator{list_node<T>* _node;__list_const_iterator(list_node<T>* node):_node(node){}const T& operator*(){return _node->_val;}__list_const_iterator<T>& operator++(){_node = _node->_next;return *this;}bool operator!=(const __list_const_iterator<T>& node){return _node != node._node;}};
之后再把这个类丢进去。
但是这样会发现,实现的太过繁杂了。
这里就来个优化版本。
ii 优化实现
这里先直接上结果
list中的重命名:
typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*>const_iterator;
具体实现:
template<class T, class ref>struct __list_iterator{list_node<T>* _node;__list_iterator(list_node<T>* node):_node(node){}ref& operator*(){return _node->_val;}__list_iterator<T, ref, ptr>& operator++(){_node = _node->_next;return *this;}bool operator!=(const __list_iterator<T, ref, ptr>& node){return _node != node._node;}};
这里是给模板新添加了一个参数。
从而实现const与普通的两种类型迭代器的实现。
六. 整体代码
//迭代器部分template<class T,class ref>struct __list_iterator{list_node<T>* _node;__list_iterator(list_node<T>* node):_node(node)ref& operator*(){return _node->_val;}__list_iterator<T,ref>& operator++(){_node = _node->_next;return *this;}__list_iterator<T, ref>& operator++(int){__list_iterator<T, ref>(*this);_node = _node->_next;return *this;}__list_iterator<T, ref>& operator--(){_node = _node->_prev;return *this;}__list_iterator<T, ref>& operator--(int){__list_iterator<T, ref>(*this);_node = _node->_prev;return *this;}bool operator!=(const __list_iterator<T, ref>& node){return _node != node._node;}};
//list中的public命名部分
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T, const T&,const T*>const_iterator;
相关文章:
List中的迭代器实现【C++】
List中的迭代器实现【C】 一. list的结构二. 迭代器的区别三. 迭代器的实现i. 类的设计ii. 重载iii. !重载iiii. begin()iiiii. end()iiiii. operator* 四.测试五. const迭代器的实现i. 实现ii 优化实现 六. 整体代码 一. list的结构 其实按照习惯来说,应该要专门出…...
VB.NET三层之用户查询窗体
目录 前言: 过程: UI层代码展示: BLL层代码展示: DAL层代码展示: 查询用户效果图: 总结: 前言: 想要对用户进行查询,需要用到控件DataGrideView,通过代码的形式将数据库表中的数据显示在DataGrideview控件中,不用对DatGridView控件…...
Django之路由层
文章目录 路由匹配语法路由配置注意事项转换器注册自定义转化器 无名分组和有名分组无名分组有名分组 反向解析简介普通反向解析无名分组、有名分组之反向解析 路由分发简介为什么要用路由分发?路由分发实现 伪静态的概念名称空间虚拟环境什么是虚拟环境?…...
【06】VirtualService高级流量功能
5.3 weight 部署demoapp v10和v11版本 --- apiVersion: apps/v1 kind: Deployment metadata:labels:app: demoappv10version: v1.0name: demoappv10 spec:progressDeadlineSeconds: 600replicas: 3selector:matchLabels:app: demoappversion: v1.0template:metadata:labels:app…...
322. 零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种硬币的数量是无限的。 示…...
【大模型-第一篇】在阿里云上部署ChatGLM3
前言 好久没写博客了,最近大模型盛行,尤其是ChatGLM3上线,所以想部署试验一下。 本篇只是第一篇,仅仅只是部署而已,没有FINETUNE、没有Langchain更没有外挂知识库,所以从申请资源——>开通虚机——>…...
2023-11-14 mysql-主从复制-相关文档
摘要: 2023-11-14 mysql-主从复制-相关文档 官方文档: MySQL :: MySQL 8.0 Reference Manual :: 17 Replication MySQL :: MySQL 8.0 Reference Manual :: 18 Group Replication 相关参数: mysql> show variables like %repl%; +-----------------------------------------…...
ios 对话框 弹框,输入对话框 普通对话框
1 普通对话框 UIAlertController* alert [UIAlertController alertControllerWithTitle:"a" message:"alert12222fdsfs" pr…...
(论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
文献阅读笔记(分层卷积特征) 简介 题目 Hierarchical Convolutional Features for Visual Tracking 作者 Chao Ma, Jia-Bin Huang, Xiaokang Yang and Ming-Hsuan Yang 原文链接 arxiv.org/pdf/1707.03816.pdf 关键词 Hierarchical convolution…...
基于IGT-DSER智能网关实现GE的PAC/PLC与罗克韦尔(AB)的PLC之间通讯
工业自动化领域的IGT-DSER智能网关模块支持GE、西门子、三菱、欧姆龙、AB等各种品牌的PLC之间通讯(相关资料下载),同时也支持PLC与Modbus协议的工业机器人、智能仪表等设备通讯。网关有多个网口、串口,也可选择WIFI无线通讯。无需编程开发,只…...
创建符合 Web 可访问性标准的 HTML 布局
人们常说网络可访问性是当今万维网的“必须”。“Web 可访问性”一词定义了开发人员需要遵循的一组准则,以使残障人士和 Web 应用程序的交互更加方便。任何网站的内容、UI/UX 设计和布局都应该易于访问。在本文中,Logicify团队为 HTML/CSS 开发人员提供了…...
SQL学习(CTFhub)整数型注入,字符型注入,报错注入 -----手工注入+ sqlmap注入
目录 整数型注入 手工注入 为什么要将1设置为-1呢? sqlmap注入 sqlmap注入步骤: 字符型注入 手工注入 sqlmap注入 报错注入 手工注入 sqlmap注入 整数型注入 手工注入 先输入1 接着尝试2,3,2有回显,而3没有回显…...
数字人部署之VITS+Wav2lip数据流转处理以提高实时性
一、模型 VITS模型训练教程VITS-从零开始微调(finetune)训练并部署指南-支持本地云端 Wav2lip是2D数字人,可参考训练嘴型同步模型Wav2Lip PS:以上模型都是开源可用。 二. VITS数据处理问题 VITS模型的输出为一维的numpy类型数据ÿ…...
GPT 学习法:复杂文献轻松的完美理解、在庞大的不确性中找到确定性
GPT 学习法:复杂文献轻松的完美理解、在庞大的不确性中找到确定性 复杂文献 - 基础理解GPT 理解法 - 举例子、归纳、逻辑链推导本质、图示、概念放大器GPT 分析法 - 二分、矩阵、公式、要素、过程 做复杂题:在庞大的不确性中找到确定性思维追踪ÿ…...
前端简单的爱心形状
首先需要创建一个 HTML 文件,然后在其中添加 CSS 样式和 JavaScript 代码。以下是一个简单的示例: 创建一个名为 loveheart.html 的文件 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><…...
acwing算法基础之数学知识--求数a的欧拉函数值phi(a)
目录 1 基础知识2 模板3 工程化 1 基础知识 数a的欧拉函数 ϕ ( a ) \phi(a) ϕ(a):表示1~n中与n互质的数的个数。其中两个数互质,是指这两个数的最大公约数为1。 根据定义,我们可以写出如下方法, int gcd(int a, int b) {retu…...
Jenkins的介绍与相关配置
Jenkins的介绍与配置 一.CI/CD介绍 1.CI/CD概念 ①CI 中文意思是持续集成 (Continuous Integration, CI) 是一种软件开发流程,核心思想是在代码库中的每个提交都通过自动化的构建和测试流程进行验证。这种方法可以帮助团队更加频繁地交付软件&#x…...
开源网安受邀参加网络空间安全合作与发展论坛,为软件开发安全建设献计献策
11月10日,在广西南宁举办的“2023网络空间安全合作与发展论坛”圆满结束。论坛在中国兵工学会的指导下,以“凝聚网络空间安全学术智慧,赋能数字经济时代四链融合”为主题,邀请了多位专家及企业代表共探讨网络安全发展与数字经济…...
arcgis提取栅格有效边界
方法一:【3D Analyst工具】-【转换】-【由栅格转出】-【栅格范围】 打开一幅栅格数据,利用【栅格范围】工具提取其有效边界(不包含NoData值): 方法二:先利用【栅格计算器】将有效值赋值为1,得到…...
后端接口性能优化分析-问题发现问题定义
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码🔥如果感觉博主的文章还不错的话,请👍三连支持&…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...
Python 解释器安装全攻略(适用于 Linux / Windows / macOS)
目录 一、Windows安装Python解释器1.1 下载并安装Python解释1.2 测试安装是否成功1.3 设置pip的国内镜像------永久配置 二、macOS安装Python解释器三、Linux下安装Python解释器3.1 Rocky8.10/Rocky9.5安装Python解释器3.2 Ubuntu2204/Ubuntu2404安装Python解释器3.3 设置pip的…...
【docker】Windows安装docker
环境及工具(点击下载) Docker Desktop Installer.exe (windows 环境下运行docker的一款产品) wsl_update_x64 (Linux 内核包) 前期准备 系统要求2: Windows 11:64 位系统&am…...
MATLAB生成大规模无线通信网络拓扑(任意节点数量)
功能: 生成任意节点数量的网络拓扑,符合现实世界节点空间分布和连接规律 效果: 30节点: 100节点: 500节点: 程序: %创建时间:2025年6月8日 %zhouzhichao %自然生长出n节点的网络% …...
18-Oracle 23ai JSON二元性颠覆传统
在当今百花齐放的多模型数据库时代,开发人员常在关系型与文档型数据库间艰难取舍。Oracle Database 23ai推出的JSON关系二元性(JSON Relational Duality) 和二元性视图(Duality Views) 创新性地统一了两者优势…...
华为云Flexus+DeepSeek征文|华为云一键部署知识库搜索增强版Dify平台,构建智能聊天助手实战指南
目录 前言 1 架构描述 2 资源栈创建流程详解 2.1 选择部署模板 2.2 参数配置内容 2.3 资源栈设置选项 2.4 配置确认与执行方式 3 部署过程与控制台反馈 3.1 实时资源监控 3.2 资源详情与访问路径 3.3 模板与事件管理 4 知识库构建流程 4.1 数据导入操作 4.2 文本…...
