之前我们在stl的学习中使用了迭代器来遍历我们的容器,我知道了迭代器是一个非常好用的工具,我们可以正向遍历我们的容器;现在我们来实现我们的反向迭代器,反向遍历我们的容器;
先附上我的代码:
my_road: 我的代码 (gitee.com)->stl模拟实现->模拟实现reverse_iterator;
我们首先看reverse_iterator的代码:
我们现在代入的是在list容器上实现反向迭代器(反向迭代器是所有容器通用的,我们现在只是带入list这个容器的情况去理解我们的反向迭代器):
//迭代器
typedef list_iterator<T,T&,T*> iterator;
typedef list_iterator<T,const T&,const T*> const_iterator;
//反向迭代器
typedef list_reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef list_reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
//反向迭代器接口
reverse_iterator rbegin()
{
return reverse_iterator(_head);
}
reverse_iterator rend()
{
return reverse_iterator(_head->_next);
}
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(_head);
}
const_reverse_iterator rend()const
{
return const_reverse_iterator(_head->_next);
}
namespace my_reverse_iterator {
template<class iterator, class Ref, class Ptr>
struct list_reverse_iterator
{
typedef list_reverse_iterator<iterator, Ref, Ptr> reverse_iterator;
iterator _it;
list_reverse_iterator(iterator p)
:_it(p)
{}
Ref operator *()
{
iterator tmp = _it;
tmp--;
return *tmp;
}
Ptr operator ->()
{
iterator tmp = _it;
tmp--;
return &tmp._node->_data;
}
reverse_iterator& operator ++()
{
return _it--;
}
reverse_iterator operator ++(int)
{
iterator tmp = _it;
_it--;
return tmp;
}
reverse_iterator& operator --()
{
return _it++;
}
reverse_iterator operator --(int)
{
iterator tmp = _it;
_it++;
return tmp;
}
bool operator!=(const reverse_iterator& it)const
{
return it._it != _it;
}
bool operator==(const reverse_iterator& it)const
{
return it._it == _it;
}
};
}
我们可以看到反向迭代器的模板参数有三个,后面两个在我们讲list的迭代器的时候我们就讲过了,我们现在就看这个第一个模板参数iterator,这个模板参数就像它的名字一样,它就是迭代器,我们的模板参数居然是一个迭代器!为啥要把反向迭代器的模板参数写进来一个迭代器呢,我们就和之前写普通的迭代器一样传三个参数T,T&,T*这样不也可以实现吗?
下面就是我们直接重载++实现我们的list的反向迭代器;
//迭代器
typedef list_iterator<T,T&,T*> iterator;
typedef list_iterator<T,const T&,const T*> const_iterator;
//反向迭代器
typedef list_reverse_iterator<T, T&, T*> reverse_iterator;
typedef list_reverse_iterator<T, const T&, const T*> const_reverse_iterator;
//直接重载++成反向迭代器
template<class T, class Ref, class Ptr>
struct list_reverse_iterator
{
typedef list_node<T> node;
typedef list_reverse_iterator<T, Ref, Ptr> iterator;
node* _node;
list_reverse_iterator(node* p)
:_node(p)
{}
Ref operator *()
{
return _node->_data;
}
Ptr operator ->()
{
return &_node->_data;
}
iterator& operator ++()
{
return _node->_prev;
}
iterator operator ++(int)
{
node* tmp = _node;
_node = _node->_prev;
return tmp;
}
iterator& operator --()
{
return _node->_next;
}
iterator operator --(int)
{
node* tmp = _node;
_node = _node->_next;
return tmp;
}
bool operator!=(const iterator& it)
{
return it._node != _node;
}
bool operator==(const iterator& it)
{
return it._node == _node;
}
};
既然可以直接这样实现那为什么还要多此一举传一个迭代器作为参数呢?
其实这并不是多此一举,因为我们看上面的代码是不是和我们的普通迭代器的代码相差无几呢?并且这样我们是不是每种容器都要去实现一种反向迭代器,这样的过程太冗余了,而我们迭代器提供的接口其实是相似的,当我们还在想怎么实现一个容器的迭代器的时候,我们的stl大佬已经开始在想怎么设计兼容的反向迭代器了,写一个所有容器都可以通用的反向迭代器!
而我们传递迭代器作为模板参数,这样我们就是对我们的迭代器进行操作了,既然是对迭代器进行操作,那这样的话所有容器都有迭代器,而且迭代器提供的接口都是一样的(因为迭代器是所有容器都有的,通用的工具的实现的接口一定是相同的)所以我们反向迭代器的实现以迭代器为底层也可以实现通用!这就是我们的思维和大佬思维的差距!站在巨人的肩膀上学习呀!
接下来我们看看我们实现需要注意的地方,我们的反向迭代器的rbegin和rend的位置是和迭代器相对的这样是为了兼容我们所有容器的迭代器;
就像这张图一样,我们的反向迭代器的rbegin和rend正好是和迭代器相对的,这样也导致我们的解引用操作获得的是我们这个反向迭代器的上一个位置的值:
看,我们解引用返回就是我们上一个位置值;
这就是为什么要返回上一个位置的原因,因为我们遍历的范围都是左闭右开的;反向迭代器也是一样的只不过左右换了个位置;
其他的接口只不过就是重载了我们的++和--的行为,其实我们实现的代码不是很难,难的是我们想到这样子写兼容代码的思维;
以上就是我对reverse_iterator的理解了
2023.11.16;