[ C++ ] STL---反向迭代器的模拟实现

news2024/11/17 22:34:18

目录

前言:

反向迭代器简介

list反向迭代器的模拟实现

 反向迭代器的模拟实现(适配器模式)

SGI版本STL反向迭代器源码

STL库中解引用操作与出口设计

适配list的反向迭代器

适配vector的反向迭代器


前言:

反向迭代器是一种特殊类型的迭代器,它可以逆向遍历容器中的元素,与正向迭代器相比,反向迭代器从容器的末尾开始,向前遍历到容器的起始位置,反向迭代器提供了一种方便的方式来反向访问容器中的元素,特别适用于需要逆序处理数据的场景;

C++标准库中,反向迭代器通常通过rbegin()和rend()成员函数来获取,一般情况下,rbegin()返回指向容器最后一个元素的迭代器,而rend()返回指向容器起始位置前一个元素的迭器;

反向迭代器简介

#include <iostream>
#include <list>
using namespace std;
int main()
{
	list<int> lt;
	lt.push_back(10);
	lt.push_back(20);
	lt.push_back(30);
	lt.push_back(40);
	lt.push_back(50);

	//正向遍历
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//反向遍历
	list<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	return 0;
}

运行结果:

list反向迭代器的模拟实现

思考一: 

从行为方式上,反向迭代器与正向迭代器的区别是什么?

正向迭代器与反向迭代器的除了++、- -等接口外毫无区别

若只实现链表的反向迭代器,如何实现?

链表普通迭代器实现入口:[ C++ ] STL---list的模拟实现-CSDN博客

链表反向迭代器实现步骤:

  1. 拷贝普通迭代器,类名修改为__List_reverse_iterator
  2. 修改前置++、后置++、前置--、后置-- 接口
  3. list类中重定义reverse_iterator与const_reverse_iterator
//list反向迭代器实现代码
template<class T, class Ref, class Ptr>
struct __List_reverse_iterator//修改类名
{
	typedef ListNode<T> Node;
	Node* _node;
	__List_reverse_iterator(Node* node)
		:_node(node)
	{}
	typedef __List_reverse_iterator<T> self;

	//修改++/--接口的指向
	self& operator++()
	{
		_node = _node->_prev;
		return *this;
	}
	//it++
	self operator++(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	//--it
	self& operator--()
	{
		_node = _node->_next;
		return *this;
	}
	//it--
	self operator--(int)
	{
		self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	bool operator==(const self& s)
	{
		return _node == s._node;
	}
	bool operator!=(const self& s)
	{
		return _node != s._node;
	}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
};

template<class T>
class list
{
	typedef ListNode<T> Node;
public:
    //list类中重定义
	typedef __List_reverse_iterator<T, T&, T*> reverse_iterator;//重命名反向迭代器
	typedef __List_reverse_iterator<T, const T&, const T*> const_reverse_iterator;//重命名const反向迭代器

	//......

private:
	Node* _head;
};

 反向迭代器的模拟实现(适配器模式)

上述实现list反向迭代器的方式会在同一份文件中,存在普通迭代器与反向迭代器两个类并且两个类中仅有个别接口略有差异,代码冗余,导致可读性变差,更好的实现方案是什么?

解决方案:

vector/list/二叉树等容器均要面临反向迭代器的实现问题,如此便采用适配器模式,即链表的正向迭代器适配(改造)出链表的反向迭代器,vector的正向迭代器适配(改造)出vector的反向迭代器

SGI版本STL反向迭代器源码

//stl_iterator.h文件
template <class _Iterator>
class reverse_iterator 
{
protected:
  _Iterator current;
public:
  typedef typename iterator_traits<_Iterator>::iterator_category
          iterator_category;
  typedef typename iterator_traits<_Iterator>::value_type
          value_type;
  typedef typename iterator_traits<_Iterator>::difference_type
          difference_type;
  typedef typename iterator_traits<_Iterator>::pointer
          pointer;
  typedef typename iterator_traits<_Iterator>::reference
          reference;

  typedef _Iterator iterator_type;
  typedef reverse_iterator<_Iterator> _Self;

public:
  reverse_iterator() {}
  explicit reverse_iterator(iterator_type __x) : current(__x) {}

  reverse_iterator(const _Self& __x) : current(__x.current) {}
#ifdef __STL_MEMBER_TEMPLATES
  template <class _Iter>
  reverse_iterator(const reverse_iterator<_Iter>& __x)
    : current(__x.base()) {}
#endif /* __STL_MEMBER_TEMPLATES */
    
  iterator_type base() const { return current; }
  reference operator*() const {
    _Iterator __tmp = current;
    return *--__tmp;
  }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

  _Self& operator++() {
    --current;
    return *this;
  }
  _Self operator++(int) {
    _Self __tmp = *this;
    --current;
    return __tmp;
  }
  _Self& operator--() {
    ++current;
    return *this;
  }
  _Self operator--(int) {
    _Self __tmp = *this;
    ++current;
    return __tmp;
  }

  _Self operator+(difference_type __n) const {
    return _Self(current - __n);
  }
  _Self& operator+=(difference_type __n) {
    current -= __n;
    return *this;
  }
  _Self operator-(difference_type __n) const {
    return _Self(current + __n);
  }
  _Self& operator-=(difference_type __n) {
    current += __n;
    return *this;
  }
  reference operator[](difference_type __n) const { return *(*this + __n); }  
}; 
//stl_list.h文件
reverse_iterator rbegin() 
{ 
return reverse_iterator(end()); 
}
const_reverse_iterator rbegin() const 
{ 
return const_reverse_iterator(end()); 
}

reverse_iterator rend()
{ 
return reverse_iterator(begin()); 
}
const_reverse_iterator rend() const
{ 
return const_reverse_iterator(begin()); 
}

STL库中解引用操作与出口设计

STL库中设计了一种对称结构,正向迭代器的开始位置为反向迭代器的结束位置,反向迭代器的开始位置即正向迭代器的结束位置

适配list的反向迭代器

实现思路:

将正向迭代器作为模板参数传递给反向迭代器的成员变量cur,如此反向迭代器就可以自动匹配容器,反向迭代器就可以统一实现复用了:

//ReverseIterator.h文件
//第一个模版参数为正向迭代器,利用正向迭代器改造反向迭代器;
//第二个模版参数Ref定义反向迭代器的数据类型,数据类型分为const类型/非const类型;
//第三个模版参数Ptr定义自定义类型指针所指向的数据的的读写属性;
template<class Iterator,class Ref,class Ptr>
struct ReverseIterator
{
	//成员变量cur,cur为正向迭代器类所定义的对象
	Iterator cur;
	//ReverseIterator<Iterator,Ref,Ptr> operator++()
	typedef ReverseIterator<Iterator, Ref, Ptr> Self;
	Self& operator++()
	{
		--cur;//调用cur对象所属类的operator--()函数
		return *this;
	}
	Self operator++(int)
	{
		Self tmp(cur);
		--cur;
		return tmp;
	}
	Self& operator--()
	{
		++cur;//调用cur对象所属类的operator++()函数
		return *this;
	}
	Self operator--(int)
	{
		Self tmp(cur);
		++cur;
		return tmp;
	}
	// !=/== 本质比较正向迭代器也即结点的指针
	bool operator!=(const Self& s)
	{
		return cur != s.cur;
	}
	bool operator==(const Self& s)
	{
		return cur == s.cur;
	}
	//构造函数(正向迭代器构造反向迭代器)
	ReverseIterator(Iterator it)
		:cur(it)
	{}
	Ref operator*()
	{
		Iterator tmp = cur;
		--tmp;
		return *tmp;
	}
	//需要对象指针即对象地址,所以先解引用再取&
	Ptr operator->()
	{
		return &(operator*());
	}
};
list类中统一名称并且需要提供出口;
//list.h文件代码节选
template<class T>
class list
{
typedef ListNode<T> Node;
public:
typedef __List_iterator<T, T&, T*> iterator;
typedef __List_iterator<T, const T&, const T*> const_iterator;

//list类中统一名称
typedef  ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef  ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;

//搭配出口,list类中实现rbegin()、rend()
reverse_iterator rbegin()
{
	return reverse_iterator(end());
}
reverse_iterator rend()
{
	return reverse_iterator(begin());
}
//......
}

适配vector的反向迭代器

//vector.h文件代码节选
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;

//vector中统一名称
typedef  ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef  ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;


//搭配出口,vector中实现rbegin()、rend()
reverse_iterator rbegin()
{
	return reverse_iterator(end());
}
reverse_iterator rend()
{
	return reverse_iterator(begin());
}
//......
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};

欢迎大家批评指正,博主会持续输出优质内容,谢谢大家观看,码字画图不易,希望大家给个一键三连支持~ 你的支持是我创作的不竭动力~

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

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

相关文章

C语言函数和数组

目录 一.数组 一.一维数组&#xff1a; 1.一维数组的创建: 2.一维数组的初始化&#xff1a; 3.一维数组的使用 4.一维数组在内存中的存储&#xff1a; 二.二维数组&#xff1a; 三.数组越界&#xff1a; 四.数组作为函数参数&#xff1a; 二.函数 一.函数是什么&…

Redis I/O多路复用

I/O多路复用 Redis的I/o多路复用中&#xff0c;将多个连接放到I/O复用程序中&#xff0c;这个复用程序具体是什么&#xff0c;是Redis的主线程吗 在Redis的I/O多路复用机制中&#xff0c;“复用程序”实际上指的是操作系统提供的系统调用接口&#xff0c;如Linux下的epoll、sel…

Unity 学习日记 8.2D物理引擎

1.2D刚体的属性和方法 2.碰撞器

探索 Flutter 中的 NavigationRail:使用详解

1. 介绍 在 Flutter 中&#xff0c;NavigationRail 是一个垂直的导航栏组件&#xff0c;用于在应用程序中提供导航功能。它通常用于更大屏幕空间的设备&#xff0c;如平板电脑和桌面应用程序。NavigationRail 提供了一种直观的方式来浏览应用程序的不同部分&#xff0c;并允许…

【并发编程】锁相关公平锁和非公平锁?可重入锁锁的升级乐观锁和悲观锁版本号机制CAS 算法乐观锁有哪些问题?

目录 ​编辑 锁相关 公平锁和非公平锁&#xff1f; 可重入锁 锁的升级 乐观锁和悲观锁 版本号机制 CAS 算法 乐观锁有哪些问题&#xff1f; 锁相关 公平锁和非公平锁&#xff1f; 公平锁 : 锁被释放之后&#xff0c;先申请的线程先得到锁。性能较差一些&#xff0c;因…

第六届“传智杯”决赛 流水账 | 珂学家

前言 整体评价 有幸参加了第六届的传智杯决赛(A组)&#xff0c;因为这个比赛是牛客协办&#xff0c;所以就写在这里。 作为Java选手&#xff0c;比赛中其实吃亏了&#xff0c;主要是T2吃了一发TLE&#xff0c;T4吃了一发莫名其妙的MLE。 顺便吐槽下T3&#xff0c;自测反馈WA…

局域网内的手机、平板、电脑的文件共享

在日常工作生活中&#xff0c;经常需要将文件在手机、平板、电脑间传输&#xff0c;以下介绍三种较为便捷的方法&#xff1a; 1.LocalSend 该软件是免费开源的&#xff0c;可以在局域网内的任意手机、平板、电脑间传递文件&#xff0c;并且任意一方都可以作为“发送方”和“接…

Windows11 安装confluence 7.4.0

Windows11安装confluence:7.4.0 1.打开终端管理员(管理员权限的PowerShell)2.按顺序执行以下命令,安装confluence服务3.浏览器(如Microsoft Edge) 打开 http://127.0.0.1:8100/ 配置confluence4.图示 本文是Windows11 安装confluence 7.4.0的步骤 本文参考 1.打开终端管理员(管…

⾃定义类型:结构体

目录 1. 结构体类型的声明 1.1 结构体回顾 1.1.1 结构的声明 1.1.2 结构体变量的创建和初始化 1.2 结构的特殊声明 1.3 结构的⾃引⽤ 2. 结构体内存对⻬ 2.1 对⻬规则 2.2 为什么存在内存对⻬? 2.3 修改默认对⻬数 3. 结构体传参 4. 结构体实现位段 4.1 什么是位段…

tcp 协议详解

什么是 TCP 协议 TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制。TCP 是一个传输层的协议。 如下图&#xff1a; 我们接下来在讲解 TCP/IP 协议栈的下三层时都会先解决这两个问题&#xff1a; 报头与有效载荷如何…

基于Springboot的艺体培训机构业务管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的艺体培训机构业务管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…

数据结构——树与二叉树

目录 树与二叉树 1.树的定义 2.树的有关术语 3.二叉树&#xff08;BinaryTree&#xff09; 二叉树的性质&#xff1a; 特殊的二叉树 满二叉树&#xff1a; 完全二叉树 二叉树的存储结构 顺序存储结构 链式存储结构 二叉树以及对应接口的实现 1.二叉树架构搭建 2…

docker将本地镜像pull到阿里云和registry

目录 一、上次到阿里云服务器 1、制作一个带有vim功能的Ubuntu镜像 2、在阿里云上面创建镜像仓库 3、从阿里云仓库中上传和拉取镜像 二、上传镜像到本地私有库registry 1、下载镜像docker registry 2、运行私有库registry&#xff0c;相当于本地有个私有docker hub。 3…

MUNIK第二届功能安全及自动驾驶研讨会将在沪召开

2024年4月26日,由上海秒尼科技术服务有限公司(以下简称“Munik”)联合Parosoft主办的“第二届功能安全及自动驾驶研讨会”将在上海虹桥隆重开幕。 据了解,本次功能与自动驾驶安全研讨会,将聚焦在ISO 26262标准体系下,自动驾驶新形势下各个零部件供应商如何满足功能安全等相关重…

Ubuntu Desktop 快速显示桌面

Ubuntu Desktop 快速显示桌面 1. 快捷方式2. show desktop iconReferences 1. 快捷方式 Ctrl Win D&#xff1a;快速显示桌面 / 恢复屏幕显示 2. show desktop icon System Settings -> Appearance -> Add show desktop icon to the launcher ​ 点击 Show Desktop…

Druid连接池的能力介绍与使用方法

Druid连接池的能力介绍与使用方法 本文将介绍druid连接池的能力&#xff1a;监控sql调用数据&#xff08;慢sql、调用量、异常堆栈&#xff09;、防止sql注入和数据库密码加密。 1. Druid连接池简介 Alibaba Druid官网使用手册里是这样介绍的&#xff1a;Druid连接池是阿里巴…

云原生网络魔术师:Docker高级网络实战演练与深度解析

在Docker的世界中&#xff0c;网络无疑是一块充满魔力的土地。当我们超越了基础的网络配置&#xff0c;步入Docker高级网络领域时&#xff0c;你会发现一个全新的、强大而灵活的网络模型正在等待你的探索。本文将带你亲历Docker高级网络实战操作&#xff0c;揭开overlay网络、自…

【动态规划】Leetcode 70. 爬楼梯

【动态规划】Leetcode 70. 爬楼梯 解法1 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 输入…

GaussDB WDR分析之集群报告篇

AWR报告目前已经成为Oracle DBA分析问题&#xff0c;定位故障最为重要的报告&#xff0c;阅读与分析AWR报告的技能也是Oracle DBA必备的技能。国产数据库为了提高运维便捷性&#xff0c;都在做类似Oracle AWR报告的模仿&#xff0c;只不过由于指标体系不够完善&#xff0c;因此…

Windows系统安装WampServer结合内网穿透实现公网访问本地服务

文章目录 前言1.WampServer下载安装2.WampServer启动3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 前言 Wamp 是一个 Windows系统下的 Apache PHP Mysql 集成安装环境&#xff0c;是一组常用来…