前言
前面我们在模拟实现vector,list的实现,源码中不仅有正向迭代器,const迭代器,其实还有反向迭代器。
本篇博客我们就来实现一下反向迭代器,并收获新的思考
一. 反向迭代器分析
在前面的学习,我们知道正向迭代器的使用
如下是vector的迭代器使用
//正向迭代器
vector<int>::iterator it = v1.begin();
while(it != v1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
而反向迭代器的使用是这样的
vector<int>::reverse_iterator rit = v1.rbegin();
while (rit != v1.rend())
{
cout << *rit << " ";
rit++;
}
cout << endl;
如图所示,我们发现,反向迭代器其实和正向迭代器基本一致。
其本质都是指针。
差别是
- 正向迭代器的遍历是通过重载++,其本质是跳转到当前节点的next
- 正向迭代器的起始位置是v.begin(),其指向数组的第一个元素
- 正向迭代器的结束位置是v.end(),其指向数组最后一个元素的下一个位置
而反向迭代器的实现应该是这样的
- 反向迭代器的遍历也是通过重载++,但其本质是跳转到当前节点的prev
- 反向迭代器的起始位置是v.rbegin(),其指向数组的最后一个元素
- 反向迭代器的结束位置是v.rend(),其指向数组第一个元素的前一个位置
通过以上分析,我们就可以在正向迭代器的基础上,实现反向迭代器了
二. 第一种实现
以下,示范list的反向迭代器的实现
//反向迭代器
template<class T, class Ref, class Ptr>
struct _list_reverse_iterator
{
typedef list_node<T> node;
typedef _list_reverse_iterator<T, Ref, Ptr> self;//因为需要返回迭代器,所以重命名一下
//成员变量
node* _node;
//构造函数
_list_iterator(node* x)
:_node(x)
{}
//operator*重载
Ref&operator*()
{
return _node->_date;
}
Ptr operator->()
{
return &_node->_date;
}
//operator前置++重载
self& operator ++()
{
_node = _node->_prev;
return *this;//返回迭代器本身
}
//operator后置++重载
self operator++(int)
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
//operator前置--重载
self& operator --()
{
_node = _node->_next;
return *this;//返回迭代器本身
}
//operator后置--重载
self operator--(int)
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
//operator==重载
bool operator ==(const self&s)
{
return _node == s._node;
}
//operator!=重载
bool operator!=(const self&s)
{
return _node != s._node;
}
};
和【C++STL】-- list的模拟实现中的正向迭代器基本一致
只有前置/后置的++/--有所改变
还需要在list类中实现rbegin和rend的函数接口
typedef _list_reverse_iterator<T, T&, T*> reverse_iterator;
reverse_iterator rbegin()
{
return reverse_iterator(_head->_prev);
}
reverse_iterator rend()
{
return reverse_iterator(_head);
}
简单测试一下
void list_test8()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
list<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
cout << *rit << " ";
++rit;
}
cout<<endl;
}
三. 第二种实现 – 泛型编程
1. 问题
对于上述的实现,是正确的。但是再反观正向迭代器的实现,我们发现二者很多代码都是一样的,只有部分有所差异。而我们仅实现了list的反向迭代器,vector的也还需要编写
但是其实vector的反向迭代器也和其正向迭代器相差不大
那么此时泛型编程的强大就体现于此
既然每个容器的反向迭代器都和其本拥有的正向迭代器相差不大的话,那何不把反向迭代器封装成单独一个.h呢,然后去适配每个容器的正向迭代器
2. 实现
"iterator.h"
template<class Iterator,class Ref,class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> self;
Iterator _cur;
ReverseIterator(Iterator it)
:_cur(it)
{}
//因为rbegin返回的是end()的位置,所以需要--才能访问到数据
Ref operator*()
{
Iterator tmp = _cur;
--tmp;
return *tmp;
}
Ptr operator->()
{
return &_cur->_date;
}
self& operator++()
{
--_cur;
return *this;
}
self& operator++(int)
{
self tmp(*this);
--_cur;
return tmp;
}
self operator--()
{
++_cur;
return *this;
}
self operator--(int)
{
self tmp(*this);
++_cur;
return tmp;
}
bool operator !=(const self&s)
{
return _cur != s._cur;
}
bool operator ==(const self&s)
{
return _cur == s._cur;
}
};
lish.h
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*>const_reverse_iterator;
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
无论我们需要什么容器的反向迭代器,我们只需要将该容器的正向迭代器作为模板参数传给ReverseIterator,然后编写相应的rbegin和rend函数就好
结束语
本章对反向迭代器的学习就到这了,感谢阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。