文章目录
反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代器,++ 运算将访问前一个元素,而 -- 运算则访问下一个元素
所有容器都定义了 begin 和 end 成员,分别返回指向容器首元素和尾元素下一位置的迭代器。这两个迭代器通常用于标记包含容器中所有元素的迭代范围。容器还定义了 rbegin 和 rend 成员,分别返回指向容器尾元素和首元素前一位置的反向迭代器。与普通迭代器一样,反向迭代器也有const和非const版本
综上,反向迭代器的特点如下:
- rbegin()相当于end()
- rend()相当于begin()
- 反向迭代器++相当于正向迭代器–
- 其他操作* != ->和正向迭代器相同
反向迭代器和正向迭代器的使用完全相同
void vector_reverse_iterator_test()
{
hdp::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
hdp::vector<int>::reverse_iterator rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
}

我们可以通过参考STL源码中的反向迭代器的实现方式来学习如何实现反向迭代器
//vector反向迭代器
template <class T, class Alloc = alloc>
class vector {
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef reverse_iterator<const_iterator, value_type, const_reference,
difference_type> const_reverse_iterator;
typedef reverse_iterator<iterator, value_type, reference, difference_type>
reverse_iterator;
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());
}
}
// list反向迭代器
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_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
}
我们可以看到,STL中vector和list的反向迭代器都是reverse_iterator类的typedef,而reverse_iterator类位于源码的stl_iterator.h中,其中部分源码如下:
template<typename _Iterator>
class reverse_iterator
{
protected:
_Iterator current;
public:
reverse_iterator()
: current()
{}
reverse_iterator(iterator_type __x)
: current(__x)
{}
reference operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
}
pointer operator->() const
{
return &(operator*());
}
reverse_iterator& operator++()
{
--current;
return *this;
}
reverse_iterator operator++(int)
{
reverse_iterator __tmp = *this;
--current;
return __tmp;
}
reverse_iterator& operator--()
{
++current;
return *this;
}
reverse_iterator operator--(int)
{
reverse_iterator __tmp = *this;
++current;
return __tmp;
}
}


如上图我们可以知道,正向迭代器是reverse_iterator的模板参数,而反向迭代器是reverse_iterator的对象,所以反向迭代器是一个容器适配器,它的适配容器是对应的正向迭代器,这样它就可以根据传递过来的正向迭代器的不同实例化出对应的反向迭代器,所以,只要我们实现了reverse_iterator类,不管是任何容器,只要支持反向迭代器,就可以传递其正向迭代器作为参数,就能够适配出对应的反向迭代器。
我们有几个需要注意的地方:
1.我们为了其对称性,使得rbegin()等价于end(),rend()等价于begin(),所以++reverse_iterator等价于–iterator,–reverse_iterator等价于++iterator;由于end是指向最后一个元素的下一个位置,而rbegin由end适配得到,所以反向迭代器中的operator*()不是返回迭代器的当前位置的数据,而是返回迭代器当前位置的前一个位置的数据,如果我们需要返回当前位置的数据,可以将rbegin()由–end(),rend()由–begin()进行适配即可。
2.我们在实现operator*()和operator->()时,我们不知道T的类型(const/非const),所以我们不能确定函数的返回值类型,在STL源码中使用迭代器萃取的方法来解决这个问题
template<typename _Iterator>
class reverse_iterator
public:
typedef _Iterator iterator_type;
typedef typename __traits_type::difference_type difference_type;
typedef typename __traits_type::pointer pointer;
typedef typename __traits_type::reference reference;
protected:
_Iterator current;
typedef iterator_traits<_Iterator> __traits_type;
reference
operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
}
pointer
operator->() const
{ return &(operator*()); }
但是这种方式实现得比较复杂,所以我们像正向迭代器那样增加两个模板参数分别作为operator*()和operator->()的函数返回值即可:
template<class Iterator,class Ref,class Ptr>
class ReverseIterator
{
Ref& operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
// 返回节点的地址
Ptr operator->()
{
return &(operator*());
}
}
完整代码如下:
template<class Iterator,class Ref,class Ptr>
class ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> Self;
public:
// 构造
ReverseIterator(Iterator it)
:_it(it)
{}
// 解引用返回的是最后一个位置的前一个数据
Ref& operator*()
{
Iterator tmp = _it;
return *(--tmp);
}
// 返回节点的地址
Ptr operator->()
{
return &(operator*());
}
Self& operator++()
{
--_it;
return *this;
}
// 后置++,返回值不加引用,tmp是局部变量
Self operator++(int)
{
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;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
private:
// 成员变量为正向迭代器
Iterator _it;
};
vector迭代器
namespace hdp
{
template<class T>
class vector
{
public:
// 迭代器
typedef T* iterator;
typedef const T* const_iterator;
// 反向迭代器
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
// 迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
// const 迭代器
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
// 反向迭代器
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
// const反向迭代器
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}
}
}
list迭代器
namespace hdp
{
template<class T>
class list
{
// 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 ReverseIterator<iterator,T&,T*> reverse_iterator;
typedef ReverseIterator<const_iterator,const T&,const T*> const_reverse_iterator;
// 迭代器
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
// iterator it(_head);
// return it;
// 匿名对象构造
return iterator(_head);
}
// const 迭代器
const_iterator begin() const
{
return const_iterator(_head->_next);
}
const_iterator end() const
{
return const_iterator(_head);
}
// 反向迭代器
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
// const 反向迭代器
const_reverse_iterator rbegin() const
{
const_reverse_iterator(end());
}
const_reverse_iterator rend() const
{
const_reverse_iterator(begin());
}
}
}
它是一种通用的遍历方式,所有的容器都可以使用迭代器这种方式去访问修改,对于string类来说,无论是正向遍历,还是反向遍历,下标+[]都足够好用,但是对于其他容器,对于那些以链表形式连接的数据结构,如list,map/set等,就不能使用下标+[]的方式去访问容器里的元素,所以就需要采用迭代器来访问这些容器里的元素。
根据迭代器实现的不同功能,C++迭代器分为:输入迭代器,输出迭代器,正向迭代器,双向迭代器,随机迭代器。
(1)输入迭代器:从容器中读取元素。输入迭代器只能一次读入一个元素向前移动,输入迭代器只支持一遍算法,同一个输入迭代器不能两次遍历一个序列
(2)输出迭代器:向容器中写入元素。输出迭代器只能一次一个元素向前移动。输出迭代器只支持一遍算法,同一输出迭代器不能两次遍历一个序列
(3)正向迭代器:假设 p 是一个正向迭代器,则 p 支持以下操作:++p,p++,*p。此外,两个正向迭代器可以互相赋值,还可以用==和!=运算符进行比较。实际对应的类型有:forward_list,unordered_mapunordered_set。
(4)双向迭代器:双向迭代器具有正向迭代器的全部功能。除此之外,若 p 是一个双向迭代器,则–p和p–都是有定义的。–p使得 p 朝和++p相反的方向移动。实际对应的类型有:list,map,set。
(5)随机迭代器:随机访问迭代器具有双向迭代器的全部功能。若 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:
p+=i:使得 p 往后移动 i 个元素。
p-=i:使得 p 往前移动 i 个元素。
p+i:返回 p 后面第 i 个元素的迭代器。
p-i:返回 p 前面第 i 个元素的迭代器。
p[i]:返回 p 后面第 i 个元素的引用。
此外,两个随机访问迭代器 p1、p2 还可以用 < > <= >=运算符进行比较。p1 < p2的含义是:p1 经过若干次(至少一次)++操作后,就会等于 p2。其他比较方式的含义与此类似。
对于两个随机访问迭代器 p1、p2,表达式p2-p1也是有定义的,其返回值是 p2 所指向元素和 p1 所指向元素的序号之差(也可以说是 p2 和 p1 之间的元素个数减一)。
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
我最近开始编写Ruby代码,但我对block参数有误解。以下面的代码为例:h={#Ahashthatmapsnumbernamestodigits:one=>1,#The"arrows"showmappings:key=>value:two=>2#ThecolonsindicateSymbolliterals}h[:one]#=>1.Accessavaluebykeyh[:three]=3#Addanewkey/valuepairtothehashh.eachdo|key,value|#Iteratethroughthekey/valuepairsprint"#{value}:#{ke
我想从特定索引开始遍历数组。我该怎么做?myj.eachdo|temp|...end 最佳答案 执行以下操作:your_array[your_index..-1].eachdo|temp|###end 关于ruby-从特定索引开始迭代数组,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/44151758/
我正在用ruby遍历一个数组。有没有一种简单的方法可以在不返回for循环的情况下获取迭代次数或数组索引? 最佳答案 啊,知道了。each_with_index哇!编辑:糟糕! 关于ruby-如何使用每个迭代器获取数组索引或迭代次数?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/706115/
我在阅读有关.each迭代器的Ruby问题,有人说如果更高阶的迭代器更适合该任务,则使用.each可能会产生代码味道。Ruby中的高阶迭代器是什么?编辑:我提到的StackOverflow答案的作者JörgWMittag提到他是要编写更高级别的迭代器,但他还解释了下面的内容。 最佳答案 哎呀。我的意思是更高级别的迭代器,而不是更高阶的迭代器。当然,每个迭代器都是高阶的。基本上,迭代是一个非常低级的概念。编程的目的是与团队中的其他利益相关者交流意图。“初始化一个空数组,然后遍历另一个数组,并将该数组的当前元素添加到第一个数组中(如果该
给定一个最小整数和最大整数,我想创建一个数组,它从最小值到最大值以二为单位计数,然后倒退(再次以二为单位,重复最大数)。例如,如果最小数是1,最大数是9,我想要[1,3,5,7,9,9,7,5,3,1].我试图尽可能简洁,这就是我使用单行代码的原因。在Python中,我会这样做:range(1,10,2)+range(9,0,-2)在我刚刚开始学习的Ruby中,到目前为止我所想到的是:(1..9).inject([]){|r,num|num%2==1?r这行得通,但我知道必须有更好的方法。这是什么? 最佳答案 (1..9).step
我的背景是PHP和C#,但我真的很想学习RoR。为此,我开始阅读官方文档。我对一些代码示例有一些疑问。第一个是迭代器:classArraydefinject(n)each{|value|n=yield(n,value)}nenddefsuminject(0){|n,value|n+value}enddefproductinject(1){|n,value|n*value}endend我理解yield的意思是“在这里执行关联的block”。令我震惊的是|value|n=each的一部分。其他block对我来说更有意义,因为它们似乎模仿C#风格的lambda:publicintsum(in
我知道我可以用这段代码迭代liquid模板中的数组:{%foriteminmyarray%}{{item.label}}但是我怎样才能得到我的项目在数组中的索引呢? 最佳答案 根据"LiquidforDesigners"liquid的github部分...forloop.length#=>lengthoftheentireforloopforloop.index#=>indexofthecurrentiterationforloop.index0#=>indexofthecurrentiteration(zerobased)forl
我在使用Ruby时遇到了初期问题,涉及创建单向、惰性求值、可能无限的迭代器。基本上,我尝试像使用Haskell列表一样使用Ruby,并在较小程度上使用Python生成器。并不是我不理解它们本身;而是我不理解它们。我只是不知道如何像其他语言一样随意使用它们,而且我也不确定Ruby中的哪些方法会在我背后将它们变成数组,从而不必要地将整个序列卸载到内存中。是的,我一直在研究Ruby引用手册。实际上,专心地进行了半个小时。或许显然不是。例如,如果我要实现一个卡片组,它在Python中看起来像这样(未经测试):#Python3fromitertoolsimportchain,countface_
有没有一种简单的说法:否则,如果没有任何循环,则显示“无对象”。似乎应该有一个很好的语法方法来执行此操作而不是计算@user.find_object("param")的长度 最佳答案 你可以这样做:if@collection.blank?#@collectionwasemptyelse@collection.eachdo|object|#Youriterationlogicendend 关于ruby-on-rails-在RubyonRails的每个循环中,如果没有任何迭代,是否有做某事的