C++的stack和queue类(三):适配所有容器的反向迭代器

目录

前言

list的反向迭代器 

list.h文件

ReverseIterator.h文件

test.cpp文件


前言

迭代器按性质分类:

  • 单向:forward_list
  • 双向:list
  • 随机:vector / deque

迭代器按功能分类:

  • 正向
  • 反向
  • const

list的反向迭代器 

问题:反向迭代器和正向迭代器的不同点在哪?

答:二者功能类似,只是++和--的方向不一样

基本概念:本来每个容器都要写一个反向迭代器的类,但是这样太费劲了,我们只需要写一个反向迭代器的类模板给编译器,传不同的容器的正向迭代器实例化,编译器帮助我们实例化出各种容器的对应反向迭代器

list.h文件

#pragma once
#include<assert.h>
#include"ReverseIterator.h"namespace bit
{template<class T>struct ListNode{ListNode<T>* _next;ListNode<T>* _prev;T _data;ListNode(const T& x = T()):_next(nullptr), _prev(nullptr), _data(x){}};//正向迭代器的类模板
///template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;// typedef ListIterator<T, T&, T*>// typedef ListIterator<T, const T&, const T*>typedef ListIterator<T, Ref, Ptr> iterator;Node* _node;ListIterator(Node* node):_node(node){}// *it//T& operator*()Ref operator*(){return _node->_data;}// it->//T* operator->()Ptr operator->(){return &_node->_data;}// ++ititerator& operator++(){_node = _node->_next;return *this;}iterator operator++(int){iterator tmp(*this);_node = _node->_next;return tmp;}iterator& operator--(){_node = _node->_prev;return *this;}iterator operator--(int){iterator tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const iterator& it){return _node != it._node;}bool operator==(const iterator& it){return _node == it._node;}};//list类模板
///template<class T>class list{typedef ListNode<T> Node;public://<容器类>typedef ListIterator<T, T&, T*> iterator;//正向迭代器的类模板typedef ListIterator<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;//const反向迭代器的类模板//普通反向迭代器(const没写)reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}iterator begin(){return _head->_next;}iterator end(){return _head;}// const迭代器,需要是迭代器不能修改,还是迭代器指向的内容?// 迭代器指向的内容不能修改!const iterator不是我们需要const迭代器// T* const p1// const T* p2const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list(){empty_init();}//C++11的initializer_listlist(initializer_list<T> il){empty_init();for (auto& e : il){push_back(e);}}// lt2(lt1)list(const list<T>& lt){empty_init();for (auto& e : lt){push_back(e);}}// 需要析构,一般就需要自己写深拷贝// 不需要析构,一般就不需要自己写深拷贝,默认浅拷贝就可以void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}// lt1 = lt3list<T>& operator=(list<T> lt){swap(lt);return *this;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}~list(){clear();delete _head;_head = nullptr;}/*void push_back(const T& x){Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;}*/void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void insert(iterator pos, const T& val){Node* cur = pos._node;Node* newnode = new Node(val);Node* prev = cur->_prev;// prev newnode cur;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;_size--;return iterator(next);}size_t size() const{return _size;}bool empty(){return _size == 0;}private:Node* _head;size_t _size;};
}

ReverseIterator.h文件

#pragma once// 所有容器的反向迭代器
// 迭代器适配器
namespace bit
{// vector<T>::iterator// list<T>::iteratortemplate<class Iterator, class Ref, class Ptr>struct ReverseIterator{// typedef ReverseIterator<T, T&, T*>// typedef ReverseIterator<T, const T&, const T*>typedef ReverseIterator<Iterator, Ref, Ptr> rever_iterator;//将反向迭代器的类型重命名为rever_iteratorIterator _it;//定义一个正向迭代器类型的对象,并对其进行初始化和封装ReverseIterator(Iterator it)//反向迭代器的对象由正向迭代器的对象初始化:_it(it){}Ref operator*(){Iterator tmp = _it;//不改变原迭代器本身的指向,只想获取迭代器指向的下一个位置的数据的值return *(--tmp);}Ptr operator->(){return &(operator*());//返回该对象地址,返回值的类型是Ptr*,匿名指针}//++和--逻辑与正向迭代器相反//前置++rever_iterator& operator++()//返回类型是一个反向迭代器类类型的引用{--_it;return *this;}//前置--rever_iterator& operator--(){++_it;return *this;}bool operator!=(const rever_iterator& s){return _it != s._it;}};
}

test.cpp文件

#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
#include"list.h"//list必须放在这,list.h中有需要以上头文件的地方,不改变其它代码的前提下放在上面几行会报错int main()
{bit::list<int> lt = { 1,2,3,4 };bit::list<int>::reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";++rit;}cout << endl;return 0;
}
  • lt是一个被多参数实例化的一个list类类型的对象
  • rit是一个反向迭代器类型的对象,先调用lt中的rbegin函数,该函数又会调用end函数返回一个实例化好的普通正向迭代器类类型的匿名对象,然后该匿名对象会作为参数传递给ReverseIterator类模板,从而实例化出一个反向迭代器类类型的对象,最后返回给rit

  • 调用lt的rend函数,经过一系列操作后返回一个反向迭代器类类型的匿名对象,rit和该匿名对象一起传入rit的!=重载函数中进行比较,该函数又会调用二者正向迭代器中的!=重载函数,最后将比较结果返回
  • *rit会调用rit中的*重载函数,生成一个临时的正向迭代器类型的对象tmp(_it是由正向迭代初始化的)--tmp调用正向迭代器的--重载函数令tmp指向的前一个对象,调用tmp的*重载函数返回获取的数据(运用临时对象原迭代器指向的对象不变)
  • ++rit调用rit的++重载函数,先调用_it的--重载函数将_it指向前一个对象并返回更新后的_it,最后++重载函数返回更新后的_it

~over~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

elementUI 下拉框加提示文案

效果如下&#xff1a; 展示文案在最下面&#xff0c;跟选项有个分割线 <el-select v-model"value" placeholder"请选择" clearable popper-class"addNotice" class"addNoticeS" visible-change"(v) >selectNotice(v,展示…

独一无二:探索单例模式在现代编程中的奥秘与实践

设计模式在软件开发中扮演着至关重要的角色&#xff0c;它们是解决特定问题的经典方法。在众多设计模式中&#xff0c;单例模式因其独特的应用场景和简洁的实现而广受欢迎。本文将从多个角度详细介绍单例模式&#xff0c;帮助你理解它的定义、实现、应用以及潜在的限制。 1. 什…

书生·浦语大模型实战营 | 第3次学习笔记

前言 书生浦语大模型应用实战营 第二期正在开营&#xff0c;欢迎大家来学习。&#xff08;参与链接&#xff1a;https://mp.weixin.qq.com/s/YYSr3re6IduLJCAh-jgZqg 第三堂课的视频链接&#xff1a;https://www.bilibili.com/video/BV1QA4m1F7t4/ 本次笔记是学习完第三堂课…

vueRouter动态路由(实现菜单权限控制)

一、权限控制管理&#xff1a; 对于企业级的项目, 我们可能需要对项目做权限控制管理, 实现不同角色的用户登录项目根据所拥有的权限访问不同的页面内容&#xff0c;此时就需要使用到动态路由来对权限页面做限制。 【使用vue-router实现动态路由&#xff0c;达到实现菜单权限…

FFmpeg: 简易ijkplayer播放器实现--06封装打开和关闭stream

文章目录 流程图stream openstream close 流程图 stream open 初始化SDL以允许⾳频输出&#xff1b;初始化帧Frame队列初始化包Packet队列初始化时钟Clock初始化音量创建解复用读取线程read_thread创建视频刷新线程video_refresh_thread int FFPlayer::stream_open(const cha…

Docker 学习笔记(七):介绍 Dockerfile 相关知识,使用 Dockerfile 构建自己的 centos 镜像

一、前言 记录时间 [2024-4-12] 系列文章简摘&#xff1a; Docker学习笔记&#xff08;二&#xff09;&#xff1a;在Linux中部署Docker&#xff08;Centos7下安装docker、环境配置&#xff0c;以及镜像简单使用&#xff09; Docker 学习笔记&#xff08;三&#xff09;&#x…

【MoS2】应变增强的单层MoS2光电探测器

这篇文章的标题是《Strain-Enhanced Large-Area Monolayer MoS2 Photodetectors》&#xff0c;作者是Borna Radatovic等人&#xff0c;发表在《ACS Applied Materials & Interfaces》期刊的2024年第16卷。文章主要研究了应变增强的大面积单层MoS2光电探测器的性能和应用潜力…

【安全】挖矿木马自助清理手册

一、什么是挖矿木马 挖矿木马会占用CPU进行超频运算&#xff0c;从而占用主机大量的CPU资源&#xff0c;严重影响服务器上的其他应用的正常运行。黑客为了得到更多的算力资源&#xff0c;一般都会对全网进行无差别扫描&#xff0c;同时利用SSH爆破和漏洞利用等手段攻击主机。 …

GC垃圾回收

垃圾回收 1、什么是 垃圾回收机制&#xff1a; 理解Java的垃圾回收机制&#xff0c;就要从&#xff1a;“什么时候”&#xff0c;“对什么东西”&#xff0c;“做了什么”三个方面来具体分析。 ​ 第一&#xff1a;“什么时候”即就是GC触发的条件。 ​ GC触发的条件有两种…

相机模型浅析

相机模型 文章目录 相机模型四个坐标系针孔相机模型世界坐标系到相机坐标系相机坐标系到图像坐标系图像坐标到像素坐标 四个坐标系 ①世界坐标系&#xff1a;是客观三维世界的绝对坐标系&#xff0c;也称客观坐标系。因为数码相机安放在三维空间中&#xff0c;我们需要世界坐标…

【opencv】示例-image_alignment.cpp 利用ECC 算法进行图像对齐

affine imshow("image", target_image); imshow("template", template_image); imshow("warped image", warped_image); imshow("error (black: no error)", abs(errorImage) * 255 / max_of_error); homography 这段代码是一个利用EC…

【300套】基于Springboot+Vue的Java毕业设计项目(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享300的Java毕业设计&#xff0c;基于Springbootvue框架&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业…

银行司库系统应用架构介绍

继国务院国资委印发了《关于推动中央企业加快司库体系建设进一步加强资金管理的意见》以及《关于中央企业加快建设世界一流财务管理体系的指导意见》&#xff0c;司库体系建设开始得到了更多重视。其中&#xff0c;作为改革风向标&#xff0c;央企数字化转型及司库建设对整个行…

【YUNBEE云贝-进阶课】MySQL8.0性能优化实战培训

众多已经学习过MySQL 8.0 OCP认证专家的课程的同学们对 MySQL 8.0 的安装部署、体系结构、配置监控、用户管理、主从复制、系统运维、MGR等基础操作和动手实验有了一定的学习基础.很多学员反馈希望更进一步提升技术能力、解决工作中碰到的性能问题。 针对MySQL8.0的数据库性能优…

Ubuntu 20.04 设置开启 root 远程登录连接

Ubuntu默认不设置 root 帐户和密码 Ubuntu默认不设置 root 帐户和密码 Ubuntu默认不设置 root 帐户和密码 如有需要&#xff0c;可在设置中开启允许 root 用户登录。具体操作步骤如下&#xff1a; 操作步骤 1、首先使用普通用户登录 2、设置root密码 macw:~$ sudo passwd …

基于STM32F103单片机的时间同步项目

一、前言 本项目为前一个时间同步项目的更迭版本&#xff0c;由于之前的G031开发板没有外部晶振&#xff0c;从机守时能力几乎没有&#xff0c;5秒以上不同步从机时间就开始飞了。在考虑成本选型后&#xff0c;选择了带有外部有缘晶振的STM32F103C8T6最小单片机&#xff0c;来作…

DRF的认证、权限、限流、序列化、反序列化

DRF的认证、权限、限流、序列化、反序列化 一、认证1、直接用&#xff0c;用户授权2、认证组件源码3、第三方认证djangorestframework-simplejwt 二、权限1. 直接使用&#xff0c;用户权限2.权限组件源码 三、序列化1. 序列化1.1 自定义Serailizer类序列化1.2 在视图APIView中使…

嵌入式驱动学习第七周——GPIO子系统

前言 GPIO子系统是用来统一便捷地访问实现输入输出中断等效果。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xff0c;一起讨论一起学习。现在关注就是老粉啦&#xff0…

spring boot整合Redis监听数据变化

一、前言 Redis提供了数据变化的通知事件&#xff0c;可以实时监测key和value的变化&#xff0c;客户端可以通过订阅相关的channel来接收这些通知事件&#xff0c;然后做相应的自定义处理&#xff0c;详细的介绍可以参考官方文档Redis keyspace notifications | Docs 使用Red…

httpsok-快速申请谷歌SSL免费证书

&#x1f525;httpsok-快速申请谷歌SSL免费证书 使用场景&#xff1a; 部署CDN证书、OSS云存储证书证书类型&#xff1a; 单域名 多域名 通配符域名 混合域名证书厂商&#xff1a; ZeroSSL Lets Encrypt Google证书加密类型&#xff1a; ECC、 RSA 一、证书管理 进入 证书管…