文章目录

  • 一、什么是反向迭代器
  • 二、STL 源码中反向迭代器的实现
  • 三、reverse_iterator 的模拟实现
  • 四、vector 和 list 反向迭代器的实现

一、什么是反向迭代器

C++ 中一共有四种迭代器 – iterator、const_iterator、reverse_iterator 以及 const_reverse_iterator,其中正向迭代器我们已经很熟悉了,其实反向迭代器的使用和正向迭代器几乎一样,反向迭代器的特点如下:

  • rbegin() 相当于 end();
  • rend() 相当于 begin();
  • 反向迭代器++相当于正向迭代器–;
  • 其他操作比如 * != -> 和正向迭代器相同。

反向迭代器的使用:反向迭代器的使用和正向迭代器完全相同

void reverse_iterator_test() {vector<int> v;v.push_back(1);v.push_back(5);v.push_back(6);v.push_back(5);v.push_back(9);vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()) {(*rit) += 1;cout << *rit << " ";++rit;}cout << endl;
}

在以前 string、vector 和 list 中模拟实现中我们只实现了正向迭代器,而并没有去实现反向迭代器,今天我们就来探究如何实现反向迭代器。


二、STL 源码中反向迭代器的实现

我们可以通过参考 STL 源码中反向迭代器的实现方式来学习如何实现反向迭代器,如下:

//list.h部分源码 -- SGI版
template <class T, class Alloc = alloc>
class list {public:typedef __list_iterator<T, T&, T*>             iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtypedef reverse_iterator<const_iterator> const_reverse_iterator;typedef reverse_iterator<iterator> reverse_iterator;
//vector.h部分源码 -- SGI版
template <class T, class Alloc = alloc>
class vector {public:typedef T value_type;typedef value_type* iterator;typedef const value_type* const_iterator;#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtypedef reverse_iterator<const_iterator> const_reverse_iterator;typedef reverse_iterator<iterator> reverse_iterator;

可以看到,STL 源码中 vector 和 list 的反向迭代器都是 reverse_iterator 类的 typedef,而 reverse_iterator 类位于源码中的 stl_iterator.h 中,其部分源码如下:

//stl_iterator.h -- SGI版
template <class Iterator>
class reverse_iterator {protected:Iterator current;public: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) {}reference operator*() const {Iterator tmp = current;return *--tmp;}
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {--current;return *this;}self& operator--() {++current;return *this;}//...
}

如上,正向迭代器是 reverse_iterator 的模板参数,而反向迭代器是 reverse_iterator 的对象,所以反向迭代器是一个容器适配器,它的适配容器就是对应的正向迭代器,这样它就能根据传递过来的正向迭代器的不同实例化出对应的反向迭代器

也就是说,只要实现了 reverse_iterator 类,以后不管是 vector、list、map 还是其他的容器,只要你将其对应的正向迭代器传递给我,我就能适配出对应的反向迭代器,做到泛型编程。


三、reverse_iterator 的模拟实现

模拟实现代码:iterator.h

#pragma oncenamespace thj {template<class Iterator, class Ref, class Ptr>class reverse_iterator {typedef reverse_iterator<Iterator, Ref, Ptr> self;public:reverse_iterator(Iterator it)   //构造: _it(it){}self& operator++() {  //++--_it;return *this;}self operator++(int) {  //后置++  返回值不加引用,因为tmp是局部变量Iterator tmp = _it;--_it;return tmp;}self& operator--() {  //--++_it;return *this;}self operator--(int) {  //后置--  返回值不加引用Iterator tmp = _it;++_it;return tmp;}bool operator!=(const self& s) const {  //不等于return _it != s._it;}Ref operator*() {  //解引用,返回的是反向迭代器的前一个位置Iterator tmp = _it;return *(--tmp);}Ptr operator->() {  //-> 返回节点数据的地址return &(operator*());}private:Iterator _it;  //成员变量是正向迭代器};
}

模拟实现细节

1、由于 rbegin() 等价于 end(),rend() 等价于 begin(),所以 ++reverse_iterator 等价于 --iteraor,–reverse_iterator 等价于 ++iterator;

2、在实现 operator*() 和 operator->() 时我们并不知道 T 的类型 (const 与非 const),所以我们不能确定函数的返回值;STL 源码中使用迭代器萃取的方法来解决这个问题,如下:

//stl_iterator.h部分源码
template <class Iterator>
class reverse_iterator
{// iterator_traits -- 迭代器萃取typedef typename iterator_traits<Iterator>::pointertypedef typename iterator_traits<Iterator>::reference reference;reference operator*() const {Iterator tmp = current;return *--tmp;}
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
};

但是这种方式十分复杂,并且校招的时候并不会考察萃取相关的知识,所以这里我们参考 list 正向迭代器 的设计思路 – 增加两个模板参数分别作为 operator*() 和 operator->() 函数的返回值,如下:

//typedef reverse_iterator<Iterator, T&, T*> reverse_iterator 反向迭代器
//typedef const_reverse_iterator<Iterator, const T&, const T*> const_reverse_iterator const反向迭代器template<class Iterator, class Ref, class Ptr>
class reverse_iterator {typedef reverse_iterator<Iterator, Ref, Ptr> self;public:Ref operator*() {  //解引用,特别注意:返回的是反向迭代器的前一个位置Iterator tmp = _it;return *(--tmp);}Ptr operator->() {  //-> 返回节点数据的地址return &(operator*());}private:Iterator _it;  //成员变量是正向迭代器
};

3、同时,由于 end 是指向最后一个元素的下一个位置,而 rbegin 由 end 适配得到,所以反向迭代器中 operator*() 不是返回迭代器当前位置的数据,而是返回迭代器前一个位置的数据,不然会发生越界访问。


四、vector 和 list 反向迭代器的实现

现在我们已经实现了 reverse_iterator 类,所以可以直接用 vector 和 list 的正向迭代器作为 reverse_iterator 的适配容器适配出它们的反向迭代器。

vector 反向迭代器

反向迭代器相关代码:

#include "iterator.h"
template<class T>class list{//反向迭代器typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;typedef thj::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());}};
}

list.h:

#pragma once#include <assert.h>
#include <algorithm>
#include "iterator.h"namespace thj {template<class T>struct list_node{list_node<T>* _next;//不加<T>也没错,但是写上好一些list_node<T>* _prev;T _data;list_node(const T& x)//构造:_next(nullptr), _prev(nullptr), _data(x){}};//迭代器最终版//const 迭代器 -- 增加模板参数,解决 operator*() 返回值与 operator->() 返回值问题//typedef __list_iterator<T, T&, T*> iterator;//typedef __list_iterator<T, const T&, const T*> const_iterator;//STL源码中大佬的写法,利用多个模板参数来避免副本造成的代码冗余问题template<class T, class Ref, class Ptr>struct __list_iterator  //迭代器类{typedef list_node<T> node;  //重命名list节点typedef __list_iterator<T, Ref, Ptr> Self;  //这里进行重命名是为了后续再添加模板参数时只用修改这一个地方node* _pnode;  //节点指针作为类的唯一成员变量__list_iterator(node* p):_pnode(p){}Ref operator*()  //解引用{return _pnode->_data;}Ptr operator->()  //->{return &_pnode->_data;}Self& operator++() //前置++{_pnode = _pnode->_next;return *this;}Self& operator++(int) //后置++{Self it(*this);_pnode = _pnode->_next;return it;}Self& operator--() //前置--{_pnode = _pnode->_prev;return *this;}Self& operator--(int) //后置--{Self it(*this);_pnode = _pnode->_prev;return it;}bool operator!=(const Self& it) const //!={return _pnode != it._pnode;}bool operator==(const Self& it) const  //=={return _pnode == it._pnode;}};//list 类template<class T>class list{typedef list_node<T> node;public:typedef __list_iterator<T, T&, T*> iterator;  //迭代器typedef __list_iterator<T, const T&, const T*> const_iterator; //const 迭代器//反向迭代器typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;typedef thj::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());}//迭代器iterator begin() {return iterator(_head->_next);}iterator end() {//iterator it(_head);//return it;//直接利用匿名对象更为便捷return iterator(_head);}const_iterator begin() const {return const_iterator(_head->_next);}const_iterator end() const {return const_iterator(_head);}void empty_initialize() {  //初始化 -- 哨兵位头结点_head = new node(T());_head->_next = _head;_head->_prev = _head;_size = 0;  //空间换时间,用于标记节点个数}list() {  //构造,不是list<T>的原因:构造函数函数名和类名相同,而list<T>是类型empty_initialize();}//迭代器区间构造template <class InputIterator>list(InputIterator first, InputIterator last) {empty_initialize();while (first != last){push_back(*first);++first;//first++;}}// 拷贝构造的现代写法//list(const list& lt) 官方库是这样写的,这是由于在类内类名等价于类型,但不建议自己这样写list(const list<T>& lt) {empty_initialize();  //初始化头结点,防止交换后tmp野指针不能正常的调用析构list<T> tmp(lt.begin(), lt.end());swap(tmp);}//赋值重载现代写法//list& operator=(list lt)list<T>& operator=(list<T> lt) {  //不能加引用,lt是调用拷贝构造生成的swap(lt);return *this;}~list() {  //析构clear();delete _head;_head = nullptr;}void swap(list<T>& lt) {  //交换两个链表,本质上是交换两个链表的头结点std::swap(_head, lt._head);std::swap(_size, lt._size);}size_t size() const {  //增加一个计数的成员,以空间换时间return _size;}bool empty() {  //判空return _size == 0;}void clear() {iterator it = begin();while (it != end()) {it = erase(it);}_size = 0;}void push_back(const T& x) {insert(end(), x);  //复用}void push_front(const T& x) {insert(begin(), x);  //复用}void pop_front() {erase(begin());}void pop_back() {erase(--end());}iterator insert(iterator pos, const T& x) {node* newnode = new node(x);node* cur = pos._pnode;node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;cur->_prev = newnode;newnode->_next = cur;++_size;return iterator(pos);}iterator erase(iterator pos) {assert(pos != end());node* prev = pos._pnode->_prev;node* next = pos._pnode->_next;prev->_next = next;next->_prev = prev;delete pos._pnode;--_size;return iterator(next);}private:node* _head;size_t _size;};
}

test.cpp:

void list_reverse_iterator_test() {thj::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);thj::list<int>::reverse_iterator rit = lt.rbegin();  //反向迭代器while (rit != lt.rend()) {(*rit)++;cout << *rit << " ";++rit;}cout << endl;const thj::list<int> clt(lt.begin(), lt.end());thj::list<int>::const_reverse_iterator crit = clt.rbegin();  //const反向迭代器while (crit != clt.rend()) {//(*crit)++;cout << *crit << " ";++crit;}cout << endl;
}

vector 反向迭代器

反向迭代器相关代码:

namespace thj {template<class T>class vector {public://正向迭代器typedef T* iterator;typedef const T* const_iterator;//反向迭代器 -- 容器适配器typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;typedef thj::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());}};
}

vector.h:

#pragma once
#include <iostream>
#include <assert.h>
#include <string.h>
#include <algorithm>
#include "iterator.h"namespace thj {template<class T>class vector {public://正向迭代器typedef T* iterator;typedef const T* const_iterator;iterator begin() {return _start;}iterator end() {return _finish;}const_iterator begin() const {return _start;}const_iterator end() const {return _finish;}//反向迭代器 -- 容器适配器//反向迭代器 -- 容器适配器typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;typedef thj::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());}public://---------------------------constructor------------------------------////无参构造vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}//迭代器区间构造template<class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while (first != last){push_back(*first);++first;}}//n个val构造vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);for (size_t i = 0; i < n; i++)push_back(val);}//n个val构造 -- 重载vector(int n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);for (int i = 0; i < n; i++)push_back(val);}//拷贝构造 -- 现代写法vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){vector<T> tmp(v.begin(), v.end());  //复用构造函数和swap函数swap(tmp);}//析构函数~vector() {delete[] _start;_start = _finish = _end_of_storage = nullptr;}//赋值重载vector<T>& operator=(vector<T> v)  //复用拷贝构造,存在自我赋值的问题,但不影响程序正确性{swap(v);return *this;}//---------------------------------capacity------------------------------------//size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;}bool empty() const{return _start == _finish;}//扩容void reserve(size_t n){if (n > capacity())  //reserve 函数不缩容{T* tmp = new T[n];//memcpy(tmp, _start, sizeof(T) * size());  //error//memcpy有自定义类型的浅拷贝问题,需要对每个元素使用拷贝构造进行深拷贝for (int i = 0; i < size(); i++)tmp[i] = _start[i];  //拷贝构造size_t oldSize = _finish - _start;  //记录原来的size,避免扩容不能确定_finishdelete[] _start;_start = tmp;_finish = _start + oldSize;_end_of_storage = _start + n;}}//扩容并初始化void resize(size_t n, T x = T()){if (n > capacity())  //resize 不缩容{reserve(n);}if (n > size()){while (_finish < _start + n){*_finish = x;++_finish;}}if (n < size()){_finish = _start + n;}}//------------------------------element access-------------------//T& operator[](size_t pos){assert(pos < size());  //检查越界return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}//----------------------------------modifys-----------------------------------////尾插void push_back(const T& n){if (size() == capacity()){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*_finish = n;++_finish;}//尾删void pop_back(){assert(!empty());--_finish;}//任意位置插入iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);//扩容导致 pos 迭代器失效if (size() == capacity()){size_t oldPos = pos - _start;  //记录pos,避免扩容后pos变为野指针size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);pos = _start + oldPos;  //扩容之后更新pos}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}//任意位置删除 -- erase 之后也认为 pos 迭代器失效iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator begin = pos;while (begin < _finish - 1){*begin = *(begin + 1);++begin;}--_finish;return pos;}//交换两个对象void swap(vector<T>& v){std::swap(_start, v._start);  //复用算法库的swap函数std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}void clear(){_finish = _start;}private:T* _start;T* _finish;T* _end_of_storage;};
}

test.cpp:

void vector_reverse_iterator_test() {thj::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);thj::vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()) {(*rit)++;cout << *rit << " ";++rit;}cout << endl;const thj::vector<int> cv(v.begin(), v.end());thj::vector<int>::const_reverse_iterator crit = cv.rbegin();while (crit != cv.rend()) {//(*crit)++;cout << *crit << " ";++crit;}cout << endl;
}


【C++】反向迭代器相关推荐

  1. Vector反向迭代器使用

    反向迭代器 1 反向迭代器其实没什么特殊的,他只是在遍历的方向上和普通迭代器不通而已:每一个容器里面都有Iterator(迭代器),可以从容器的begin位置到end-1位置,通过++来遍历.同样也有 ...

  2. boost::stl_interfaces模块实现反向迭代器的测试程序

    boost::stl_interfaces模块实现反向迭代器的测试程序 实现功能 C++实现代码 实现功能 boost::stl_interfaces模块实现反向迭代器的测试程序 C++实现代码 #i ...

  3. 迭代器和反向迭代器,常量迭代器和非常量迭代器

    迭代器的类型共有4种:<T>::Iiterator,<T>::const_iterator,<T>::reverse_iterator,<T>::con ...

  4. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)

    被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...

  5. c++STL的反向迭代器

    反向迭代器 反向迭代器是一种反向遍历容器的迭代器.也就是,从最后一个元素到第一个元素遍历容器.反向迭代器将自增(和自减)的含义反过来了:对于反向迭代 器,++ 运算将访问前一个元素,而 – 运算则访问 ...

  6. 插入迭代器、流迭代器、反向迭代器、移动迭代器

    文章目录 前言 插入迭代器 inserter front_inserter back_inserter iostream迭代器 istream_iterator 读取输入流 istream_itera ...

  7. std::string中的反向迭代器rbegin()和rend()

    在std::string中,有个接口是rbegin()和rend(),分别表示string字符串的倒数第一个字符和正数第一个字符: rbegin():表示string字符串的倒数第一个字符 rend( ...

  8. python反向迭代器_Python中对象迭代与反迭代的技巧总结

    一.如何实现可迭代对象和迭代器对象? 实际案例 某软件要求从网络抓取各个城市气味信息,并其次显示: 北京: 15 ~ 20 天津: 17 ~ 22 长春: 12 ~ 18 ...... 如果一次抓取所 ...

  9. Leetcode 58 之反向迭代器的使用

    题目: Given a string s consists of upper/lower-case alphabets and empty space characters' ', return th ...

  10. 【C++】迭代器、反向迭代器详解

    参考: http://c.biancheng.net/view/338.html https://blog.csdn.net/kjing/article/details/6936325 https:/ ...

最新文章

  1. Yii2.0实现微信公众号后台开发
  2. [云炬创业管理笔记]第四章把握创业机会测试6
  3. 追随自己的价值观:用研经理 Anne Diaz 职业探索之路
  4. leetcode 897. 递增顺序搜索树(中序遍历)
  5. recycleviewitem 列表加载动画_2019年Q4动画数据报告 | 伍六七之最强发型师评论数破十万...
  6. python判断对错题_可以在线答题,并且能判断对错,将错题保存起来
  7. mysql安全删除大表
  8. JavaScript:学习笔记(3)——正则表达式的应用
  9. 二维\三维绘图AutoCAD 2022 for Mac
  10. 【机器学习】判别模型vs生成模型、概率模型vs非概率模型
  11. [转]WebQQ登录过程分析
  12. android icon颜色转换工具,Android代码修改图标颜色
  13. 电脑如何设置颜色保护眼睛
  14. 【钉钉考勤打卡】--上传打卡记录
  15. 【娱见】乐视开始折腾路由器,小米与极路由还会好过吗?
  16. Equalize the Array(思维)
  17. 信捷PLC中Y0用C语言怎么表示,信捷PLC
  18. 【OpenHarmony】napi基础知识学习
  19. 打开ftp文件发生错误,请检查是否有权限
  20. 界面设计必备:常用字体规范

热门文章

  1. android 模拟器测评,逍遥安卓模拟器好用吗?评测成绩最流畅好用的安卓模拟器...
  2. Python 视频添加音频(附代码) | Python工具
  3. 什么是非对称加密?非对称加密概念
  4. 2021 年全年详细工作日、周末、节假日数据JSON
  5. 汽车 ECU 简介 软硬件架构 原理 详细总结
  6. python爬虫是干嘛的?python爬虫能做什么?
  7. 计算机技术基本的特征,信息的四个主要特征
  8. 计算机专业英语被动语态举例,计算机专业英语(第4版)
  9. python图案绘制解锁_PythonAppium实现安卓手机图形解锁案例
  10. 北京观赏银杏时间(10月下旬-11月中旬)