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;//拷贝
}
--it
Self& 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;//拷贝
}
--it
Self& 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;//拷贝
}
--it
Self& 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;//拷贝
}
--it
Self& 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;
}
};