List迭代器
迭代器就是像指针一样的东西,通过迭代器可以对容器进行访问,迭代器屏蔽了容器的底层实现细节。
在STL中list迭代器是一个双向带头循环的链表,因为底层结构是链表空间是不连续的,所有我们不能直接对节点的指针++,来得到下个节点的地址。这时我们就需要自定义一个类型,该类型可以实现迭代器的操作。
template<class T>
class __List_iterator
{
public:
node* _node;
};
类的成员变量是一个节点的指针。
需要在类中对迭代器++或者–的操作,++就是说我们需要得到下个节点的迭代器,在这里呢,迭代器就是封装的节点的指针,所以++和–也就是对节点的指针进行操作,来得到前后个节点的指针。
template<class T>
class __List_iterator
{
public:
node* _node;
typedef ListNode<T> node;
typedef __List_iterator<T> self;
public:
self& operator++()
{
_node = _node->next;
return *this;
}
self& operator--()
{
_node = _node->prev;
return *this;
}
};
当实现了迭代的++和–后,就可以通过迭代器进行加减啦,如果我们需要遍历容器此时还需要实现一个!=;也就是两个节点指针进行比较。
bool operator!=(const self& it)const
{
return _node != it._node;
}
接下来实现*和->,通过*我们可以取出节点的数据,->返回的是当前节点数据的地址。
T& operator*()
{
return _node->val;
}
T* operator->()
{
return &_node->val;
}
到这里我们完成了迭代器的基本功能,那么现在就会有一个新的问题,如果现在是一个const类型对象,此时就需要调用const迭代器,const迭代器是不允许对数据进行修改的,在上面的代码中如果使用的是const对象调用*和->,都可以完成对数据的修改,这是不对的。
- 现在有一种方案就是在创建一个类,这个类实现的const迭代器,这样写的话就会使代码存在大量的冗余。
- 另一种方法就是在迭代器的模板中在添加两个模板参数,用来确定*和->返回的类型。
template<class T, class Ref, class Ptr>
class __List_iterator
{
public:
typedef ListNode<T> node;
typedef __List_iterator<T, Ref, Ptr> self;
public:
__List_iterator(node* x)
:_node(x)
{}
bool operator!=(const self& it)const
{
return _node != it._node;
}
self& operator++()
{
_node = _node->next;
return *this;
}
self& operator--()
{
_node = _node->prev;
return *this;
}
Ref operator*()
{
return _node->val;
}
Ptr operator->()
{
return &_node->val;
}
node* _node;
};
如果是一个const迭代器,那么Ref就是const T&,Ptr就是const T*,此时我们就可以通过一个类,来实现不同的迭代器返回不同类型的结果。
反向迭代器
反向迭代器我们直接复用正向迭代器就可以
template<class iterator, class Ref, class Ptr>
class __Reverse_iterator
{
public:
typedef __Reverse_iterator<iterator, Ref, Ptr> reverse_iterator;
public:
__Reverse_iterator(const iterator& it)
:_rit(it)
{}
Ref operator*()
{
iterator tmp = _rit;
return *--tmp;
}
Ptr operator->()
{
return &operator*();
}
reverse_iterator& operator++()
{
--_rit;
return *this;
}
reverse_iterator& operator--()
{
++_rit;
return *this;
}
bool operator!=(const reverse_iterator& it)const
{
return _rit != it._rit;
}
private:
iterator _rit;
};
我们让正向迭代器的begin做反向迭代器的end,正向的end做反向的begin
反向迭代器的++复用的就是正向的–,反向的–复用的是正向的++;