1.迭代器
1.1正向迭代器
正向迭代器是用一个类封装的,迭代器类。例如:在vector,string中的迭代器就相当于一个指针,在list类中用一个类来封装一个节点,实质上也还是一个指针,迭代器就相当于指向一个节点的指针。
现在以list为例子,list的迭代器,代码如下:
//迭代器类
// 一个链表指针用迭代器封装,实质上还是一个指针
//迭代器也就相当于指向一个节点的指针
//第一种解决const类型的迭代器
//const迭代器类
template<class T>
struct ListConstIterator
{typedef ListNode<T> Node;typedef ListIterator<T> Self;Node* _node; //一个迭代器节点//迭代器构造ListConstIterator(Node* node) :_node(node){}++it前置++,返回++以后的值Self& operator++(){_node = _node->_next;return *this;}it++后置++Self operator++(int){Self tmp(*this);//浅拷贝,即两个迭代器指针指向同一个空间,直接应用默认拷贝构造_node = _node->_next;return tmp;//拷贝}--itSelf& operator--(){//向前走_node = _node->_prev;return *this;}it--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}*it解引用,返回的是数据T& operator*(){return _node->data;}==比较两个迭代器相等,即比较迭代器的位置(引用/地址)相同bool operator==(const Self& it){return _node == it._node;}//!=bool operator!=(const Self& it){return _node != it._node;}//->//返回的是数据的地址T* operator->(){return &_node->data;}
};
1.3 正向const迭代器
const迭代器和普通迭代器区别是: const迭代器指向的内容不能被修改!即为const_iterator begin() const,相当于const int *p
而迭代器器本身不能修改是const iterator begin(),也就相当于int * const p
所以普通迭代器和const迭代器的代码差异只在解引用是有差别
第一种解决方法是在普通迭代器的基础上再写一个const迭代器类,代码如下:
普通迭代器:
//const迭代器类
template<class T>
struct ListConstIterator
{typedef ListNode<T> Node;typedef ListIterator<T> Self;Node* _node; //一个迭代器节点//迭代器构造ListConstIterator(Node* node) :_node(node){}++it前置++,返回++以后的值Self& operator++(){_node = _node->_next;return *this;}it++后置++Self operator++(int){Self tmp(*this);//浅拷贝,即两个迭代器指针指向同一个空间,直接应用默认拷贝构造_node = _node->_next;return tmp;//拷贝}--itSelf& operator--(){//向前走_node = _node->_prev;return *this;}it--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}*it解引用,返回的是数据T& operator*(){return _node->data;}==比较两个迭代器相等,即比较迭代器的位置(引用/地址)相同bool operator==(const Self& it){return _node == it._node;}//!=bool operator!=(const Self& it){return _node != it._node;}//->//返回的是数据的地址T* operator->(){return &_node->data;}
};
const迭代器
//第一种解决const类型的迭代器
//const迭代器类
template<class T>
struct ListConstIterator
{typedef ListNode<T> Node;typedef ListConstIterator<T> Self;Node* _node; //一个迭代器节点//迭代器构造ListConstIterator(Node* node) :_node(node){}++it前置++,返回++以后的值Self& operator++(){_node = _node->_next;return *this;}it++后置++Self operator++(int){Self tmp(*this);//浅拷贝,即两个迭代器指针指向同一个空间,直接应用默认拷贝构造_node = _node->_next;return tmp;//拷贝}--itSelf& operator--(){//向前走_node = _node->_prev;return *this;}it--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}*it解引用,返回的是数据const T& operator*(){return _node->data;}==比较两个迭代器相等,即比较迭代器的位置(引用/地址)相同bool operator==(const Self& it){return _node == it._node;}//!=bool operator!=(const Self& it){return _node != it._node;}//->//返回的是数据的地址const T* operator->(){return &_node->data;}};
第二种解决方法:由于const迭代器和普通迭代器只有解引用重载的返回值不一样
//普通迭代器
解引用,返回的是数据T& operator*(){return _node->data;}//->//返回的是数据的地址T* operator->(){return &_node->data;}
//const迭代器
解引用,返回的是数据const T& operator*(){return _node->data;}//->//返回的是数据的地址const T* operator->(){return &_node->data;}
由于两个代码差别不大,只是重载的返回值不一样。第一种也会导致代码冗余,所以用模板来解决以下的问题,代码如下:
template<class T,class Ref,class Ptr>
struct ListIterator
{typedef ListNode<T> Node;typedef ListIterator<T,Ref,Ptr> Self;Node* _node; //一个迭代器节点//迭代器构造ListIterator(Node *node):_node(node){}++it前置++,返回++以后的值Self& operator++(){_node = _node->_next;return *this;}it++后置++Self operator++(int){Self tmp(*this);//浅拷贝,即两个迭代器指针指向同一个空间,直接应用默认拷贝构造_node = _node->_next;return tmp;//拷贝}--itSelf& operator--(){//向前走_node = _node->_prev;return *this;}it--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}*it解引用,返回的是数据//T& operator*()Ref operator*(){return _node->data;}==比较两个迭代器相等,即比较迭代器的位置(引用/地址)相同bool operator==(const Self& it){return _node == it._node;}//!=bool operator!=(const Self& it){return _node != it._node;}//->//返回的是数据的地址//T* operator->()Ptr operator->(){return &_node->data;}
};template<class T>
class list
{
public://重定义节点类名typedef ListNode<T> Node;
private:Node* _head;//哨兵位size_t _size;//链表中节点的个数public:......//第二种方法解决const迭代器类typedef ListIterator<T,T&,T*> iterator;typedef ListIterator<T,const T&,const T*> const_iterator;//迭代器的引用iterator begin(){//iterator it(_head->_next);//有名对象//return it;return iterator(_head->_next);//这是应用的是一个匿名对象}iterator end(){return iterator(_head);}//const迭代器,需要迭代器不能修改,还是迭代器指向的内容?// 迭代器指向的内容不嫩被修改! const iterator不是我们需要的const迭代器//以下是迭代器本身不能修改//const iterator begin()错误const_iterator begin() const{//iterator it(_head->_next);//有名对象//return it;return const_iterator(_head->_next);//这是应用的是一个匿名对象}const_iterator end() const{return const_iterator(_head);}
};
1.3反向迭代器和反向const迭代器
在我们主观意识上,正向迭代器的begin指向的是除去哨兵位的第一个节点,end则是指向最后一个节点下一个节点(即哨兵位头节点)。而我们也会觉得rbegin则是指向最后一个数据,rend指向第一个节点的上一个节点(即哨兵位头节点),如图
但是,在c++库中我们则见到的是将begin和rend指向的第一个节点,end和rbegin都指向哨兵位头节点,如图
但是库中的解引用时,会是先++,再解引用
//解引用
Ref operator*()
{//return *_it;//解引用的是前一个Iterator tmp = _it;return *(--tmp);
}
#include<iostream>
#include<vector>
#include<string>
using namespace std;//所有容器的反向迭代器
//迭代器适配器//给我vector<T>::iterator,list<int>::iterator//适配出相应的反向迭代器//本来,每个容器都要写一个反向迭代器的类,但是自己写,太费劲了template<class Iterator, class Ref, class Ptr>struct ReverseIterator{typedef ReverseIterator<Iterator, Ref, Ptr> Self;//重命名Iterator _it;//构造//反向迭代器封装一个正向迭代器ReverseIterator(Iterator it) :_it(it){}Ref operator*(){//return *_it;//解引用的是前一个Iterator tmp = _it;return *(--tmp);}Ptr operator->(){//return _it.operator->();return &(operator*());}//++调用迭代器中的--Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!=(const Self& s){return _it != s._it;}};