【STL】:反向迭代器

news2024/9/24 1:26:43

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关反向迭代器的模拟实现,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

前言:

1. 基本构造

2. 接口完善

3. 在list中使用反向迭代器

list反向迭代器版本一:

list反向迭代器版本二: 

4. 在vector中使用反向迭代器 


前言:

前面的模拟实现vector和list中是没有实现反向迭代器的,反向迭代器与正向迭代器相比就是从数据的末端向前面访问遍历,但是两个迭代器的用法都是一样的,++就是下一个,*就可以访问到数据,但是它具体是怎么实现的呢?我们接下来看一看:

1. 基本构造

在list的模拟实现中讲解了如何实现正向迭代器(包含const版本和非const版本)那么在本期实现反向迭代器的时候就有了一定的前车之鉴,比如const版本和非const版本不需要实现两份代码,可以采用模板实现泛型编程。

反向迭代器的构造可以使用正向迭代器来进行复用,因为反向迭代器的++就是正向迭代器里面的--,所以在传递模板参数的时候可以直接传递一个迭代器,直接复用这个迭代器里面的各种结构完成反向迭代器的构造。这种方式叫做迭代器适配器。

#pragma once

namespace ywh
{
	//反向迭代器
	template <class Iterator, class Ref, class Ptr>
	class ReverseIterator
	{
	public:
		typedef ReverseIterator<Iterator, Ref, Ptr> Self;

		//构造
		ReverseIterator(Iterator it)
			:_it(it)
		{}

	private:
		Iterator _it;
	};
}

2. 接口完善

反向迭代器的接口有++、--、*、->、!=、==,这些接口的实现都是可以通过使用模板参数中的迭代器来进行复用即可。

头文件: reverse_iterator.h

#pragma once

namespace ywh
{
	//反向迭代器
	template <class Iterator, class Ref, class Ptr>
	class ReverseIterator
	{
	public:
		typedef ReverseIterator<Iterator, Ref, Ptr> Self;

		//构造
		ReverseIterator(Iterator it)
			:_it(it)
		{}

		//前置
		//operator++
		Self& operator++()
		{
			//复用传过来的迭代器里面的operator--
			--_it;
			return *this;
		}
		//operator--
		Self&operator++()
		{
			++_it;
			return *this;
		}

		//operator*
		Ref operator*()
		{
			return *_it;
		}
		//operator->
		Ptr operator->()
		{
			return _it.operator->();
		}

		//operator==
		bool operator==(const Self& s)
		{
			return _it == s._it;
		}
		//operator!=
		bool operator!=(const Self& s)
		{
			return _it != s._it;
		}
	private:
		Iterator _it;
	};
}

3. 在list中使用反向迭代器

要使用反向迭代器,首先得在list头文件中包含以下反向迭代器的头文件,然后进行构造:

list反向迭代器版本一:

#pragma once
#include "reverse_iterator.h"
namespace ywh
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

		//构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//正向迭代器
	//   类型模板参数   传递引用      传递指针
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
		Node* _node;
		//迭代器构造
		__list_iterator(Node* node)
			:_node(node)
		{}
		
		//前置
		//operator++
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//operator--
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		//后置
		self operator++(int)
		{
			self* tmp(_node);
			_node = _node->_next;
			return tmp;
		}
		//operator--
		self operator--(int)
		{
			self* tmp(_node);
			_node = _node->_prev;
			return tmp;
		}

		//operator*
		Ref operator*()
		{
			return _node->_data;
		}
		//operator->
		Ptr operator->()
		{
			return &_node->_data;
		}
		//operator!=
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		//operator==
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		typedef __list_iterator<T, T&, T*> iterator;   //非const迭代器
		typedef __list_iterator<T, const T&, const T*> const_iterator;  //const迭代器
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;   //反向迭代器
		typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;   //反向迭代器

	public:
		基本构造///
		//...
		///正向迭代器
		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);
		}
		//反向迭代器/
		reverse_iterator rbegin()
		{
			return reverse_iterator(--end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(end());
		}
		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(--end());
		}
		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(end());
		}
		///修改相关接口
		//...
	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

list反向迭代器版本二: 

我们也可以看一下库里面list的反向迭代器如何设计:

可以看到库里面的玩法是一种对称的结构,这种对称的结构在解引用访问时访问的是下一个节点的元素,这样子写是比较好理解的,正向的起始就是反向的结束,正向的结束就是反向的起始,那么我们也可以来按照这种写法来写一下:

头文件:reverse_iterator.h

#pragma once
namespace ywh
{
	//反向迭代器
	template <class Iterator, class Ref, class Ptr>
	class ReverseIterator
	{
	public:
		typedef ReverseIterator<Iterator, Ref, Ptr> Self;

		//构造
		ReverseIterator(Iterator it)
			:_it(it)
		{}

		//前置
		//operator++
		Self& operator++()
		{
			//复用传过来的迭代器里面的operator--
			--_it;
			return *this;
		}
		//operator--
		Self&operator++()
		{
			++_it;
			return *this;
		}

		//operator*
		Ref operator*()
		{
			Iterator cur = _it;
			//返回下一个节点的数据
			return *(--cur);
		}
		//operator->
		Ptr operator->()
		{
			return _it.operator->();
		}

		//operator==
		bool operator==(const Self& s)
		{
			return _it == s._it;
		}
		//operator!=
		bool operator!=(const Self& s)
		{
			return _it != s._it;
		}
	private:
		Iterator _it;
	};
}

头文件:List.h

#pragma once
#include "reverse_iterator.h"
namespace ywh
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

		//构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//正向迭代器
	//   类型模板参数   传递引用      传递指针
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
		Node* _node;
		//迭代器构造
		__list_iterator(Node* node)
			:_node(node)
		{}
		
		//前置
		//operator++
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//operator--
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		//后置
		self operator++(int)
		{
			self* tmp(_node);
			_node = _node->_next;
			return tmp;
		}
		//operator--
		self operator--(int)
		{
			self* tmp(_node);
			_node = _node->_prev;
			return tmp;
		}

		//operator*
		Ref operator*()
		{
			return _node->_data;
		}
		//operator->
		Ptr operator->()
		{
			return &_node->_data;
		}
		//operator!=
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		//operator==
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		typedef __list_iterator<T, T&, T*> iterator;   //非const迭代器
		typedef __list_iterator<T, const T&, const T*> const_iterator;  //const迭代器
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;   //反向迭代器
		typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;   //反向迭代器

	public:
		基本构造///
		//...
		///正向迭代器
		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);
		}
		//反向迭代器/
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}
		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}
		///修改相关接口
		//...
	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

4. 在vector中使用反向迭代器 

vector中的反向迭代器不建议使用上面的版本一,因为begin()和end()是传值返回,是临时对象,而临时对象具有常性,不好进行修改,所以还是比较建议使用这种对称的结构。

头文件:Vector.h

#pragma once
#include <assert.h>
#include "reverse_iterator.h"
namespace ywh
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
	public:
		/正向迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}
		/反向迭代器/
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}
		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}
		/基本构造///
	    //...
		///容量
		//...
		///修改
		//...
	private:
		iterator _start = nullptr;   //起始位置
		iterator _finish = nullptr;  //有效数据位置
		iterator _end_of_storage = nullptr; //结束位置
	};
}


朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1228406.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【kafka】使用docker启动kafka

1.环境准备 docker拉取zookeeper镜像 docker pull zookeeper:3.4.14 创建zookeeper容器&#xff0c;默认端口号为2181 docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14 拉取kafka镜像 docker pull wurstmeister/kafka:2.12-2.3.1 创键kafka容器&#xff…

c语言-输入输出详解

文章目录 格式化输入输出占位符printfscanf 字符串输入输出puts&#xff08;&#xff09;gets&#xff08;&#xff09; 字符输入输出putchar&#xff08;&#xff09;getchar&#xff08;&#xff09; 区别 格式化输入输出 输入输出的库函数的头文件&#xff1a; #include<…

2023/11/19总结

项目进度&#xff1a; 地址管理&#xff1a; 显示菜品 购物车相关功能 然后最近在看 支付宝沙盒支付的相关功能&#xff0c;打算把支付给做了 。界面做的不是很好看 &#xff0c;但是后续会改成 手机端的。

WSL 2 更改默认安装的 Linux 发行版

目录 什么是 WSL 2&#xff1f;更改默认安装的 Linux 发行版更改发行版的 WSL 版本 什么是 WSL 2&#xff1f; WSL 2 是适用于 Linux 的 Windows 子系统体系结构的一个新版本&#xff0c;它支持适用于 Linux 的 Windows 子系统在 Windows 上运行 ELF64 Linux 二进制文件。 它的…

基于SSM的北海旅游网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

ICCV2023 Tracking paper汇总(二)(多目标跟随、单目标跟随等)

十六、Integrating Boxes and Masks: A Multi-Object Framework for Unified Visual Tracking and Segmentation paper&#xff1a; https://openaccess.thecvf.com/content/ICCV2023/papers/Xu_Integrating_Boxes_and_Masks_A_Multi-Object_Framework_for_Unified_Visual_ICC…

Android 13 - Media框架(14)- OpenMax(二)

这一节我们将来解析 media.codec 这个 HIDL service 究竟提供了什么服务&#xff0c;服务是如何启动的。 1、main 函数 我们先来看 frameworks/av/services/mediacodec/main_codecservice.cpp&#xff1a; int main(int argc __unused, char** argv) {strcpy(argv[0], "…

搭建网关服务器实现DHCP自动分配、HTTP服务和免密登录

目录 一. 实验要求 二. 实验准备 三. 实验过程 1. 网关服务器新建网卡并改为仅主机模式 2. 修改新建网卡IP配置文件并重启服务 3. 搭建网关服务器的dhcp服务 4. 修改server2网卡配置文件重启服务并效验 5. 设置主机1的网络连接为仅主机模式 6. 给server2和网关服务器之…

【Django-DRF用法】多年积累md笔记,第(4)篇:Django-DRF反序列化详解

本文从分析现在流行的前后端分离Web应用模式说起&#xff0c;然后介绍如何设计REST API&#xff0c;通过使用Django来实现一个REST API为例&#xff0c;明确后端开发REST API要做的最核心工作&#xff0c;然后介绍Django REST framework能帮助我们简化开发REST API的工作。 全…

性能测试学习——项目环境搭建和Jmete学习二

项目环境搭建、Jmeter学习二 环境的部署虚拟机的安装虚拟机中添加项目操作步骤 使用环境的注意事项Jmeter的安装和简单使用Jemter的使用的进阶Jemter元件 Jmeter属性执行顺序和作用域作用域以自定义用户变量和用户参数(前置处理器)为例如何解决用户变量和线程组同级时&#xff…

C语言之qsort()函数的模拟实现

C语言之qsort()函数的模拟实现 文章目录 C语言之qsort()函数的模拟实现1. 简介2. 冒泡排序3. 对冒泡排序进行改造4. 改造部分4.1 保留部分的冒泡排序4.2 比较部分4.3 交换部分 5. bubble_sort2完整代码6. 使用bubble_sort2来排序整型数组7. 使用bubble_sort2来排序结构体数组7.…

系列六、GC垃圾回收【四大垃圾算法-标记清除算法】

一、概述 标记清除算法分为两个阶段&#xff0c;即&#xff1a;标记和清除两个阶段&#xff0c;先标记出要回收的对象&#xff0c;然后统一回收这些对象。形如&#xff1a; 老年代一般是由标记清除或者标记清除 标记压缩的混合实现。 二、原理 用通俗的话解释一下标记清除算法…

LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索Indexes for information retrieve

接着前面的Langchain&#xff0c;继续实现读取YouTube的视频脚本来问答Indexes for information retrieve LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗…

一文了解Word2vec 阐述训练流程

一文了解Word2vec 阐述训练流程 个性嵌入&#xff08;Personality Embeddings&#xff09; 词嵌入&#xff08;Word Embeddings&#xff09; 嵌入向量效果分析 语言模型 模型介绍 模型训练 Word2vec训练方法 CBOW方法 Skip-gram方法 CBOW方法与Skip-gram方法总结 重构…

高精度算法【Java】(待更新中~)

高进度加法 在Java中可以使用BigInteger进行高精度计算&#xff0c;除此也可以仿照竖式相加的计算原理进行计算。 BigInteger 提供所有 Java 的基本整数操作符的对应物&#xff0c;并提供 java.lang.Math 的所有相关方法。另外&#xff0c;BigInteger 还提供以下运算&#xff1…

交易机器人-微信群通知

微信公众号:大数据高性能计算 1 背景 背景是基于人工去做交易本身无法做到24小时无时无刻的交易,主要是虚拟币本身它是24小时交易,人无法做到24小时盯盘,其次就是如果你希望通过配置更加复杂的规则甚至需要爬取最新的信息走模型进行量化交易的时候,就需要自己去做一些量化…

【Flink 问题集】The generic type parameters of ‘Collector‘ are missing

错误展示&#xff1a; Exception in thread "main" org.apache.flink.api.common.functions.InvalidTypesException: The return type of function main(CollectionDemo.java:33) could not be determined automatically, due to type erasure. You can give type in…

蓝桥杯单片机综合练习——工厂灯光控制

一、题目 二、代码 #include <reg52.h>sfr AUXR 0x8e; //定义辅助寄存器sbit S5 P3^2; //定义S5按键引脚 sbit S4 P3^3; //定义S4按键引脚unsigned char led_stat 0xff; //定义LED当前状态 unsigned char count 0; //定义50ms定时中断累…

我又开始贩卖焦虑了,机器视觉兄弟们,打工这生意盘不活了?让人逃离北上广深,是毒鸡汤吗?

我想大多数人和我想的一样&#xff0c;不要质疑自己的出身&#xff0c;也不必用一生去改变出身而获得融入感&#xff0c;思想富足这是我们留给自己一生最珍贵的礼物。也许一线城市容不下肉身&#xff0c;二三线城市容不下灵魂。那我回到生我养我的十八线小县城&#xff0c;这不…

【Linux】冯诺依曼体系结构、操作系统、进程概念、进程状态、环境变量、进程地址空间

目录 一、冯诺依曼体系结构二、操作系统(OS)1. 操作系统是什么2. 操作系统如何做管理3. 系统调用和库函数概念 三、进程1. 进程是什么&#xff1f;2. 描述进程-PCB3. 查看进程的方法 四、进程状态1 运行、阻塞和挂起状态2 Linux中的进程状态 五、进程优先级1. 什么是优先级2.查…