C++ STL学习之【反向迭代器】

✨个人主页: 夜 默
🎉所属专栏: C++修行之路
🎊每篇一句: 图片来源

  • A year from now you may wish you had started today.
    • 明年今日,你会希望此时此刻的自己已经开始行动了。

屹立不倒


文章目录

  • 🌇前言
  • 🏙️正文
    • 1、反向迭代器设计
      • 1.1、反向思想
      • 1.2、多参数模板
      • 1.3、极致对称
      • 1.4、其他功能
    • 2、应用于 vector
    • 3、应用于 list
    • 4、源码
  • 🌆总结


🌇前言

适配器模式是 STL 中的重要组成部分,在上一篇文章中我们学习了 容器适配器 的相关知识,即 stackqueue,除了 容器适配器 外,还有 迭代器适配器,借助 迭代器适配器,可以轻松将各种容器中的普通迭代器转变为反向迭代器,这正是适配器的核心思想

千兆网卡转换器


🏙️正文

反向迭代器适用于所有的容器,因此它是作为一个单独的 .h 文件出现的,别的容器如果想使用,直接包含就行了

1、反向迭代器设计

反向迭代器 reverse_iterator 可以用来反向遍历容器,在某些场景下很实用

反向迭代器
反向迭代器类中需要有:正向迭代器对象构造函数

template<class Iterator>
struct __reverse_iterator
{
	Iterator _cur;	//正向迭代器类

	//需要借助构造函数,构成出正向迭代器
	__reverse_iterator(Iterator cur)
		:_cur(cur)
	{}
};

注意源码中的反向迭代器设计较为复杂,涉及 萃取 等操作,为了方便学习,这里实现的是简易版本

1.1、反向思想

何谓反向?与正向相反就是反向,比如时钟正常都是顺时针转,但如果时钟逆时针选择,此时就称为反方向的钟

反方向的钟

存在 vector<int>() = {1, 2, 3, 4, 5} 不同方向的遍历结果不同

正向迭代器:正向遍历
结果:1 2 3 4 5

反向迭代器:反向遍历
结果:5 4 3 2 1

图解

注:库中的反向迭代器在设计时,为了最求极致的对称,rbegin() 指向最后一个有效元素的下一个位置,rend() 指向第一个有效元素(位置是与正向迭代器相反的)

//_cur 为正向迭代器
self& operator++()
{
	--_cur;	//你要++,我就--
	return *this;
}
self operator++(int)
{
	Iterator tmp = _cur;
	--_cur;
	return tmp;
}

self& operator--()
{
	++_cur;	//你要--,我就++,反过来操作
	return *this;
}
self operator--(int)
{
	Iterator tmp = _cur;
	++_cur;
	return tmp;
}

1.2、多参数模板

在模拟实现 list 迭代器类时,为了解决普通对象与 const 对象的代码冗余问题,引入了多参数,通过对形参传递不同的对象,变换为不同属性的迭代器;在反向迭代器类重,这一种巧妙思想也得到了继承

template<class Iterator, class Ref, class Ptr>
struct __reverse_iterator
{
	typedef __reverse_iterator<Iterator, Ref, Ptr> self;	//重命名迭代器类为 self
	Iterator _cur;	//正向迭代器类
	
	//……
};

在涉及 operator*() 时,需要返回目标对象引用,使用 Ref;同理,在涉及 operator->() 时,需要返回目标对象指针,使用 Ptr

具体返回对象(引用 / 指针)是否为 const 修饰,取决于调用方

1.3、极致对称

在反向迭代器类中,有一个十分奇怪的函数 operator*(),它返回的并非当前所指向的对象,而且上一个对象

Ref operator*()
{
	Iterator tmp = _cur;
	return *--tmp;	//返回的是上一个对象
}

原因:大佬在设计时为了追求与正向迭代器的绝对对称,故意指向位置与其保持一致,仅仅是 rend()begin() 处,rbegin()end()

反向迭代器
经过这样设计后,rbegin()rend() 函数的实现就变得简单了,此时压力给到了 operator*() 的实现

reverse_iterator rbegin() { reverse_iterator(end()); }	//开始 -> 尾
reverse_iterator rend() { reverse_iterator(begin()); }	//结束 -> 头

1.4、其他功能

假设想通过迭代器直接访问自定义对象中的成员时,需要用到 operator->() 函数,作用是取出迭代器所指向对象的指针 Ptr

Ptr operator->()
{
	return &(operator*());	//采取复用的形式
}

迭代器还需要比较函数 operator==()operator!=(),具体实现时,都是在复用具体对象的比较函数

bool operator==(const self& s)
{
	return (_cur == s._cur);
}
bool operator!=(const self& s)
{
	return (_cur != s._cur);
}

以上就是反向迭代器所必须的基础功能,如果你还想实现更多比较逻辑,如 operator<() 等,可以自己实现

反向迭代器类的完整代码:

#pragma once

namespace Yohifo
{
	template<class Iterator, class Ref, class Ptr>
	struct __reverse_iterator
	{
		typedef __reverse_iterator<Iterator, Ref, Ptr> self;	//重命名迭代器类为 self
		Iterator _cur;	//正向迭代器类

		__reverse_iterator(Iterator cur)
			:_cur(cur)
		{}

		Ref operator*()
		{
			Iterator tmp = _cur;
			return *--tmp;
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		//_cur 为普通(正向)迭代器
		self& operator++()
		{
			--_cur;
			return *this;
		}
		self operator++(int)
		{
			Iterator tmp = _cur;
			--_cur;
			return tmp;
		}

		self& operator--()
		{
			++_cur;
			return *this;
		}
		self operator--(int)
		{
			Iterator tmp = _cur;
			++_cur;
			return tmp;
		}

		bool operator==(const self& s)
		{
			return (_cur == s._cur);
		}
		bool operator!=(const self& s)
		{
			return (_cur != s._cur);
		}
	};
}

编写完成此头文件 reverse_iterator.hpp 后,任何具有正向迭代器的容器,都可以利用迭代器适配器,适配出属于自己的反向迭代器

具体使用例子可以接着往下看


2、应用于 vector

vector 模拟实现中,引入头文件 reverse_iterator.hpp,定义出反向迭代器所必须的函数

#pragma once
#include <iostream>
#include <string>
#include <assert.h>
#include <vector>	//对比测试用
#include <algorithm>	//排序所需要的头文件
#include <functional>	//仿函数头文件
#include "reverse_iterator.hpp"	//使用反向迭代器必须的头文件

using std::cin;
using std::cout;
using std::endl;
using std::string;

template<class T>
class vector
{
public:
	//……

	//=====反向迭代器=====
	typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;
	typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

	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;	//指向起始位置
	iterator _finish;	//指向有效元素的下一个位置
	iterator _end_of_storage;	//指向可用空间的下一个位置
};

通过反向迭代器进行遍历

void TestVector9()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	vector<int> v(arr, arr + sizeof(arr) / sizeof(arr[0]));

	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << " ";
		++rit;	//反向迭代器++,就是--
	}
	cout << endl;
}

结果
可以成功使用反向迭代器进行遍历


3、应用于 list

既然是迭代器适配器,那么反向迭代器也可以适用于 list

#pragma once
#include <iostream>
#include <cassert>
#include <vector>
#include "reverse_iterator.hpp"	//使用反向迭代器

using namespace std;

//……

//list本类
template<class T>
class list
{
	typedef __list_node<T> node;
	typedef T value_type;
	typedef T& refence;
	typedef const T& const_refence;
public:

	//……
	
	//=====反向迭代器=====
	typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;
	typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

	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:
	//初始化出头节点
	void empty_init()
	{
		_head = new node;
		_head->_prev = _head->_next = _head;
	}

	node* _head;	//哨兵位节点
};

通过反向迭代器对自定义类型数据进行遍历

struct B
{
	B(int a = 0, char c = 0)
		:_a(a)
		,_c(c)
	{}

	int _a;
	char _c;
};

void TestList()
{
	list<B> lb;

	lb.push_back(B(1, 'a'));
	lb.push_back(B(2, 'b'));
	lb.push_back(B(3, 'c'));

	list<B>::reverse_iterator rit = lb.rbegin();
	while (rit != lb.rend())
	{
		cout << "_a: " << rit->_a << " | " << "_c: " << rit->_c << endl;
		++rit;	//即使是反向迭代器,也是++
	}
	cout << endl;
}

结果
此时主要是用到了 operator->() 访问自定义类型中的成员变量


4、源码

关于 vectorlist (迭代器版)的源码在下面仓库中

vector(反向迭代器版)

list(反向迭代器版)


🌆总结

以上就是本篇关于 C++ STL 学习之【反向迭代器】的全部内容了,在本篇文章中,我们主要学习了反向迭代器类的思想及实现,最后分别用了 vectorlist 进行了测试,成功实现了反向遍历

如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!

如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正


星辰大海

相关文章推荐

STL 之 适配器

C++ STL学习之【容器适配器】

===============

STL 之 list 类

C++ STL学习之【list的模拟实现】

C++ STL学习之【list的使用】

===============

STL 之 vector 类

C++ STL学习之【vector的模拟实现】

C++ STL学习之【vector的使用】

感谢支持

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分布式锁-Redisson

分布式锁 1、分布式锁1.1 本地锁的局限性1.1.1 测试代码1.1.2 使用ab工具测试(单节点)1.1.3 本地锁问题演示(集群情况) 1.2 分布式锁实现的解决方案1.3 使用Redis实现分布式锁(了解即可)1.3.1 编写代码1.3.2 压测 1.4 使用Redisson解决分布式锁1.4.1 实现代码1.4.1 压测1.4.2 可…

2 常见模块库(2)

2.5 复用器与分路器模块 Mux是一种用于将多个信号组合成一个信号的模块。Mux模块的名称来源于多路复用器&#xff08;Multiplexer&#xff09;。 使用Mux可以将多个输入信号组合成一个向量或矩阵&#xff0c;以便在模型中传递和处理。Mux模块可以接受任意数量的输入信号&#x…

什么是伪原创?SEO伪原创该怎么做

伪原创是指在原有的文章或内容基础上进行修改或调整&#xff0c;以产生看起来是全新内容的文章&#xff0c;但实际上并没有创造新的价值。多数情况下&#xff0c;伪原创的目的是为了在文章相对原创的情况下&#xff0c;提高搜索引擎的排名。 一、高质量伪原创 做好伪原创&#…

C语言从入门到精通第8天(分支结构if、else、switch的使用)

分支结构if、else、switch的使用 if语句if...else语句if...else嵌套if...else if...else语句switch语句 if语句 语法&#xff1a; if(表达式){ 语句&#xff1b; } 如果表达式为真&#xff0c;则执行{}里面的语句。如果为假&#xff0c;则不执行。示例代码&#xff1a; int m…

翻译国外文章-整篇文章的翻译

chatgpt翻译是专业的吗 ChatGPT是一种AI语言模型&#xff0c;它可以用来执行各种自然语言处理任务&#xff0c;包括翻译。然而&#xff0c;ChatGPT的翻译结果并不是专业的翻译&#xff0c;因为该模型并不是专为翻译任务训练的。 虽然ChatGPT的翻译质量相对较高&#xff0c;但…

全景视角下的世界探索——三维全景地图

引言&#xff1a;随着数字技术和虚拟现实技术的发展&#xff0c;三维全景地图已成为一种新型地图展示方式&#xff0c;深受人们的关注和喜爱。三维全景地图以其真实逼真、互动性强、展示效果好等特点&#xff0c;正在越来越多的领域得到应用。 三维全景地图的特点 1.真实逼真 …

考研计算机组成原理总结(7)

一.虚拟存储器 1.基本知识 主存和辅存共同构成了虚拟存储器&#xff0c;二者在硬件和系统软件的共同管理下工作。对于应用程序员而言&#xff0c;虚拟存储器是透明的。虚拟存储器具有主存的速度和辅存的容量。 2.基本概念 虚拟存储器将主存或辅存的地址空间统一编址&#x…

Excel中的表格批量生成word表格

场景&#xff1a;测试用例excel转word 我们在项目中&#xff0c;默认情况下是用我们的excel用例模版输出测试用例。但是有的项目中&#xff0c;会要求在word版本的测试计划或者测试报告中&#xff0c;写明测试用例。而我们的测试用例&#xff0c;有的项目有上千条&#xff0c;…

ChatGPT常见问题,Access denied的解决办法

今天&#xff0c;突然想登录一登录ChatGPT&#xff0c;提示 Access denied, You do not have access to chat.openai.com 怎么办&#xff1f; “Access denied You do not have access to chat.openai.com. The site owner may have set restrictions that prevent you from ac…

基于html+css的图片展示15

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

1026. 节点与其祖先之间的最大差值(4-19日

题目&#xff1a;给定二叉树的根节点 root&#xff0c;找出存在于 不同 节点 A 和 B 之间的最大值 V&#xff0c;其中 V |A.val - B.val|&#xff0c;且 A 是 B 的祖先。 &#xff08;如果 A 的任何子节点之一为 B&#xff0c;或者 A 的任何子节点是 B 的祖先&#xff0c;那么…

2023年网络安全比赛--Windows渗透测试中职组(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.通过本地PC中渗透测试平台Kali对服务器场景20221219win进行系统服务及版本扫描渗透测试,并将该操作显示结果中1433端口对应的服务版本信息作为Flag值(例如3.1.4500)提交; 2.通过本地PC中渗透测试平台Kali对服务器场景202212…

车身控制模块BCM(Body Control Module)

1.BCM概述 车身控制模块BCM是高集成度的芯片。BCM的英文全称是Body Control Module。其控制对象是采用高灵敏度带唤醒及睡眠检测的高频收发器&#xff0c;实现车门车窗遥控上锁与开锁、电动后视镜、中控门锁、玻璃升降装置、车灯(远光灯、近光灯、位置灯、制动灯、转向灯、雾灯…

中国人民大学与加拿大女王大学金融硕士——在职读研该如何平衡学习与工作呢

边工作边考研&#xff0c;对于所有人来说都是个不小的挑战&#xff0c;每年都有大量在职生因为焦躁、压力而中途离场。学习时间碎片化&#xff0c;复习进度特别容易被工作上的事情所打断&#xff0c;再想“重新启动”就会很难。想要节省备考时间建议你读免联考的中外合作办学项…

第四章 法的效力

目录 第一节 法的效力概述 一、法的效力的意义二、法的效力的概念三、法的效力范围 第二节法的时间效力 一、法的生效时间二、法的失效时间三、法律溯及力 第三节法的空间效力 一、法的域内效力二、法的域外效力 第四节 法的对人效力 一、对人效力的原则二、我国法律的对人效力…

Vue|数据渲染

Vue 是如何将编译器中的代码转换为页面真实元素的&#xff1f;在Vue 中,自带了模板渲染,而模板的语法也非常简洁易懂。 精彩专栏持续更新↓↓↓ 微信小程序实战开发专栏 一. 数据渲染1.1 条件渲染v-ifv-show 1.2 列表渲染v-for 1.3 小结 一. 数据渲染 1.1 条件渲染 vue条件渲染…

网络性能定位

根据tcp协议进行分析 目录 一、SYN_RECV阶段 1.1 确定半连接队列是否有丢包&#xff1a; 1.2 确定全连接队列是否有丢包现象 二、close_wait 三、TIME_WAIT 四、抓包分析 重要字段&#xff1a; WireShark出现的常见提示 服务端存在问题的 客户端存在问题的 socket关闭…

机器视觉工程师必须知道机器视觉精度要思考哪些

​在和客户交流项目技术要求,这个项目,我要求的精度是0.01mm? 第一个问题:什么是精度? 精度要求0.01mm: 1.视觉重复性极差?静态?动态? 2.视觉与第三方相关性差异?极差?相关性系数? 3.整体系统误差?机械重复性误差? 4.产品尺寸公差? 第二个问题:精度与公差…

【杂凑算法篇】密码杂凑算法的安全强度

【杂凑算法篇】密码杂凑算法的安全强度 杂凑&#xff08;哈希&#xff09;算法安全强度—【蘇小沐】 文章目录 【杂凑算法篇】密码杂凑算法的安全强度&#xff08;一&#xff09;安全强度&#xff08;Security Strength)&#xff08;二&#xff09;杂凑算法的安全强度与对比总…

计算机网络笔记(方老师408课程)(持续更新)

文章目录 前言互联网概述互联网发展的三个阶段互联网标准化机构 互联网的组成边缘部分的通信方式核心部分的交换方式 我国计算机网络的发展计算机网络的类别计算机网络的性能速率、带宽、吞吐量时延时延带宽积往返时间RTT&#xff08;Round-Trip Time&#xff09;利用率非性能特…
最新文章