这篇文章通用于vector和list的反向迭代器,希望这篇文章看完你能对反向迭代器有更深的理解
---------
什么是反向迭代器
在遍历容器的时候,会有以下几种方式:
1.下标的随机访问,deque、vector和string都支持这种
2.迭代器
3.范围for
从底层来说,范围for其实就是迭代器经过包装之后的样子,这里主要说一下迭代器,这个使用的时候一般是如此使用:
当然,如果熟悉一点,可以直接上auto
在之前,我们模拟实现过vector的迭代器,这里放上代码看看:
namespace knous
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
reruen _finish;
}
const_iterator cbegin()
{
reruen _start;
}
const_iterator cend() const
{
rerurn _finis;
}
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
}
可以看到vector的迭代器其实就是指针,分别指向vector的头尾两端,因为其底层空间是连续,所以下标可以直接++,但是list就不一样了
template<class T, class Ref,class Ptr >
struct __list_iteartor
{
typedef list_node<T> Node;
typedef __list_iteartor<T, Ref, Ptr > self;
__list_iteartor(Node* Node)
:_node(Node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
//return &(operator*());
return &_node->_data;
}
bool operator!=(const self& it)
{
return _node != it._node;
}
self operator++(int)
{
_node = _node->_next;
return _node;
}
self operator++()
{
Node* tmp(*this);
_node = _node->_next;
return tmp;
}
self operator--(int)
{
_node = _node->_prev;
return _node;
}
self operator--()
{
_node = _node->_prev;
return _node;
}
Node* _node;
};
因为list底层空间并不连续,所以我们常规的一些操作无法直接使用,例如++、--,为了解决这种困难,所以将迭代器单纯封了一个类出来,上面就是list迭代器的代码
那反向迭代器应该是什么样子的,以下面这个举例子:
原本应该是1 2 3 4,现在变成了 4 3 2 1
这里借用我之前的一张图:
这张图可以很好的帮我们理解反向迭代器,其rbegin跟end指向的是同一块空间,也就是说,我们对这一块空间明面上是++,实际上是--,知道rbegin到rend,也就是begin的位置,迭代器就走完了全部。
模拟实现
明白了大致逻辑,接下来就正式开写:
这里我用list来写一个反向迭代器,随后复用到vector里面
template<class iterator, class Ref, class Ptr >
struct Reverse_iterator
{
iterator _it;
typedef Reverse_iterator<iterator,Ref, Ptr > self;
};
反向迭代器,其本质也是一个迭代器,只不过在实现方式上有所不同,这里就直接复用迭代器部分
构造
Reverse_iterator(iterator it)
:_it(it)
{}
借用它传进来的指针来初始化这个迭代器对象
解引用
这里要注意的一点是,我们的rbegin和rend跟stl库里面保持一致,它的rbegin对应的是end,而迭代器里面的end其实是头节点
iterator begin()
{
return iterator(_head->_next);
}
const_iterator begin() const
{
return const_iterator(_head->_next);
}
那我们实现的时候就要注意,如果此时rbegin是头节点,那我们对头节点解引用,返回的应该是头节点上一个节点解引用
所以写出如下代码:
Ref operator*()
{
return *(--_it);
}
++
注意反向迭代器的++实际上是正向迭代器的--,这里直接复用即可
self operator++()
{
--it;
return *this;
}
--
反向迭代器的--,实际上就是正向迭代器的++,复用
self operator-()
{
++it;
return *this;
}
!=
bool operator!=(const self& it)
{
return _it != it._it;
}
这里还要写一点,就是在list里面加一个反向迭代器的接口:
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可以调用这个反向迭代器,vector呢?
vector的复用
reverse_iterator rbegin()
{
return reverse_iterator(_finish);
}
reverse_iterator rend()
{
return reverse_iterator(_start);
}
const_reverse_iterator rcbegin()
{
reruen const_reverse_iterator(_finish);
}
const_reverse_iterator rcend() const
{
rerurn const_reverse_iterator(_start);
}
同样新增的几个参数,并且将重命名一下模板的名字
typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef Reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;
调用:
对比
这里放上全部代码:
namespace knous
{
template<class iterator, class Ref, class Ptr >
struct Reverse_iterator
{
iterator _it;
typedef Reverse_iterator<iterator, Ref, Ptr > self;
Reverse_iterator(iterator& it)
:_it(it)
{}
Ref operator*()
{
iterator tmp = _it;
return *(--tmp);
}
self operator++(int)
{
--_it;
return *this;
}
self operator--(int)
{
++_it;
return *this;
}
bool operator!=(const self& it)
{
return _it != it._it;
}
};
}
注意,要使用这个反向迭代器需要先有正向代码器,同时包上这两个typedef
typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef Reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;
即可正常使用,谢谢观看