C++:关于反向迭代器的学习分享
前言:
小编仅是一位初学者,所以对于C++的理解有限,文章大概率会出现表达不清楚可能也只是因为小编不知道如何更好表达,本文章仅作为一个学习的总结分享。
反向迭代器的概念
反向迭代器故名思意解释反向的迭代器,与正向迭代器相反。正向迭代器的遍历是从前往后进行遍历,那么反向迭代器则是从后往前进行遍历。
以下是对于反向迭代器的官方解释。
反向迭代器是一个类模板,这个类反转了双向迭代器或随机访问迭代器遍历范围的方向。
内部保持了原始迭代器(即基迭代器)的一个副本,并用来反映在 reverse_iterator
上执行的操作:每当 reverse_iterator
被递增时,它的基迭代器会被递减,反之亦然。可以随时通过调用成员函数 base
获得具有当前状态的基迭代器的副本。
可以看到反向迭代器的类模板参数是一个正向迭代器,那么就说明,只要容器支持正向迭代器就可以通过传入的正向迭代器取复用反向迭代器。那么这么做的好处就是并不需要每个支持正向迭代器的容器都要自己去写一份反向迭代器,而是直接复用反向迭代器的类模板,让编译器自身去实例化出相应的反向迭代器。
随机访问迭代器:
随机访问迭代器就是支持迭代器的+,-,++,--以及operator[ ]的操作,支持随机访问迭代器的容器有vector,string。他们的特点为是地址都是连续的一片地址空间。
双向迭代器:
双向迭代器就是仅支持迭代器的++,--操作,不支持+,-以及operator[ ],如list。因为list并不是一段连续的地址空间。
那么在使用反向迭代器的时候会发现反向迭代器是通过++,来访问上一个容器的数据。
反向迭代器的begin位置对应容器的end位置,反向迭代器的end位置对应容器的begin位置,为了方便理解,下图是一个list的begin位置以及end位置,那么相对于的就是list的反向迭代器的rbegin位置以及rend位置。
反向迭代器的实现
为了方便理解,小编简单实现了一个反向迭代器。
template<class Iterator ,class Ref ,class Ptr>
struct Reverse_iterator
{
Iterator _it;
Reverse_iterator(const Iterator& it)
:_it(it)
{}
typedef Reverse_iterator<Iterator,Ref, Ptr> self;
Ref operator*()
{
Iterator temp = _it;
return *(--temp);
}
Ptr operator ->()
{
return &(_it.operator*());
}
self& operator++()
{
--_it;
return *this;
}
self& operator--()
{
--_it;
return *this;
}
bool operator!=(const self&it) const
{
return _it != it._it;
}
};
小编的反向迭代器的类模板参数有三个:1.Iterator,2.Ref,3.Ptr。看过上期小编文章可以知道,Ref就是对模板参数T类型的引用,Pter就是模板参数T类型的指针。
反向迭代器里只有一个成员变量,这个成员变量就是一个正向迭代器的对象。那么反向迭代器的初始化其实就是通过传入的正向迭代器的参数对反向迭代器里的it进行初始化。
函数 Ref operator*()其实就==T&operator*(),访问的是容器里的数据。
函数里的操作是创建一个新的正向迭代器值,并把_it赋值给temp。接着先--temp,在解引用temp。那么这里是经历了什么操作呢?
不要忘记,反向迭代器其实是对容器的正向迭代器进行的再一次封装,必定是先有正向迭代器才会有反向迭代器。所以这里--temp操作会去调用正向迭代器的operator--。如果正向迭代器里没有那么就会报错。
下图我将拿上期文章实现的list来举例。
先对反向迭代器进行typedef,接着创建list的rbgin与rend函数,可以看到rbegin与rend都是去调用正向迭代器的begin与end。
通过上图就说明了为什么函数 Ref operator*( )中,为什么temp需要先--在解引用。temp迭代器的--会调用正向迭代器的operator--,而*temp则会调用正向迭代器的operator*( )。
那么反向迭代器的operator++()与 operator--()函数会调用正向迭代器的operator--()与operator++(),并且内部都是对正向迭代器的函数复用操作。唯一特殊的就是解引用。
反向迭代器的好处是什么
反向迭代器允许从容器的末尾向开头遍历元素。这对于一些算法或操作是非常方便的。
1.逆序输出:你可能想要从容器的最后一个元素开始打印,反向迭代器使得这一过程非常简单如list的逆序打印,相对比起C语言,简单不要太多。
2.从后向前的查找:在某些情况下,查找可能从容器的末尾开始是更高效的。
3.因为反向迭代器是一个类模板,所以可以兼容任何有正向迭代器的容器。
————那么本片文章就到这里,感谢各位观众老爷观看。