理解迭代器是学习STL的必经之路,迭代器可以看做是指针的抽象,相当于指针,不同的是,迭代器将指针的操作抽象出来,使之能适应不同数据类型,不同的容器类型。比如,常见的数组和链表,数组是连续存储的,而链表则不是,对于遍历操作,相同的是都需要从起始地址开始,到结束,不同的是operator++()的具体实现形式不同。如果能够将访问不同容器类型的指针抽象出来,就可以将容器与算法分离。
下面是一个为数组容器、链表容器编制共同显示函数的例子,通过这个例子,可以帮助我们更好的理解迭代器。
代码如下:
#include "stdafx.h"
#include<iostream>
#include<numeric>
using namespace std;
//动态数组的模板类
template<class T>
class Array
{
public:
Array(size_t n=3):m_nTotalSize(3),m_nValidSize(0){
m_pData=new T[n];
}
virtual ~Array(){
if(m_pData){
delete []m_pData;
m_pData=NULL;
}
}
void Add(const T& e){
if(m_nValidSize<m_nTotalSize){
m_pData[m_nValidSize]=e;
++m_nValidSize;
}
else{
m_nTotalSize<<=1; //容量扩展1倍
T* tmp=new T[m_nTotalSize];
memcpy(tmp,m_pData,m_nValidSize*sizeof(T));//重新分配内存空间
tmp[m_nValidSize]=e;
delete []m_pData;//将原内存空间删除
m_pData=tmp;
++m_nValidSize;
}
}
size_t size() const{
return m_nValidSize;
}
T Get(int pos){
return m_pData[pos];
}
T* begin(){//起始迭代指针
return m_pData;
}
T* end(){//终止迭代指针
return m_pData+m_nValidSize;
}
private:
int m_nTotalSize; //总容量
int m_nValidSize; //有效容量
T* m_pData; //数据
};
//Array对应的迭代器类
template<class Init>
class ArrayIterator
{
public:
ArrayIterator(Init* i):init(i){}
bool operator !=(ArrayIterator& it){
return it.init!=init;
}
void operator++(int){//后置迭代指针
init++;
}
Init operator*(){
return *init;
}
protected:
Init* init;
};
//泛型显示函数,模板参数Init是一个指针
template<class Init>
void display(Init start,Init end)
{
cout<<endl;
for(Init mid=start;mid!=end;mid++)
{
cout<<*mid<<"\t";
}
cout<<endl;
}
template<class T>
struct Node
{
Node():next(NULL){}
Node(const T& e):data(e),next(NULL){}
T data;
Node* next;
};
//单向链表类
template<class T>
class List
{
public:
List():head(NULL),tail(NULL),prev(NULL){}
~List(){
if(head!=NULL){
Node<T>* prev=head;
Node<T>* next=NULL;
while(prev!=NULL){
next=prev->next;
delete prev;
prev=next;
}
}
}
void Add(const T& e){
Node<T>* u=new Node<T>(e);
if(NULL==head){
head=u;
prev=u;
}
else{
prev->next=u;
prev=u;
}
tail=u->next;
}
Node<T>* begin(){//起始迭代指针
return head;
}
Node<T>* end(){//终止迭代指针
return tail;
}
protected:
Node<T>* head; //链表头
Node<T>* tail; //链表尾
Node<T>* prev; //当前节点
};
//重载operator<<
template<class T>
ostream& operator<<(ostream& os,Node<T>&s)
{
os<<s.data;
return os;
}
//测试代码
int _tmain(int argc, _TCHAR* argv[])
{
Array<int> a;
for(int i=0;i<5;i++)
{
a.Add(i+1);
}
for(int i=0;i<5;i++)
{
cout<<a.Get(i)<<" ";
}
ArrayIterator<int> start(a.begin());
ArrayIterator<int> end(a.end());
display(start,end);
List<int> b;
for(int i=0;i<5;i++)
{
b.Add(i+1);
}
ListIterator<Node<int>> lstart(b.begin());
ListIterator<Node<int>> lend(b.end());
display(start,end);
return 0;
}
以上代码实现了共同的显示函数,分别通过ArrayIteraror与ListIterator连接Array、List与display显示函数。
以上代码中ArrayIterator只能用在Array中,ListIterator只能用在List中,特定的容器,有特定的访问方式,应该有特定的迭代器,更合理的我们应该将ArrayIterator作为Array类的内部类,ListIterator作为List类的内部类。把迭代器类作为容器类的内部类。
代码如下所示:
//单向链表类
template<class T>
class List
{
public:
//List对应的迭代器类
class ListIterator
{
public:
ListIterator(Node<T>* i):init(i){}
bool operator !=(ListIterator& it){
return it.init!=init;
}
void operator++(int){//后置迭代指针
init=init->next;
}
Node<T> operator*(){
return *init;
}
protected:
Node<T>* init;
};
List():head(NULL),tail(NULL),prev(NULL){}
~List(){
if(head!=NULL){
Node<T>* prev=head;
Node<T>* next=NULL;
while(prev!=NULL){
next=prev->next;
delete prev;
prev=next;
}
}
}
void Add(const T& e){
Node<T>* u=new Node<T>(e);
if(NULL==head){
head=u;
prev=u;
}
else{
prev->next=u;
prev=u;
}
tail=u->next;
}
Node<T>* begin(){//起始迭代指针
return head;
}
Node<T>* end(){//终止迭代指针
return tail;
}
protected:
Node<T>* head; //链表头
Node<T>* tail; //链表尾
Node<T>* prev; //当前节点
};
测试代码2
int _tmain(int argc, _TCHAR* argv[])
{
Array<int> a;
for(int i=0;i<5;i++)
{
a.Add(i+1);
}
for(int i=0;i<5;i++)
{
cout<<a.Get(i)<<" ";
}
ArrayIterator<int> start(a.begin());
ArrayIterator<int> end(a.end());
display(start,end);
List<int> b;
for(int i=0;i<5;i++)
{
b.Add(i+1);
}
List<int>::ListIterator lstart(b.begin());//list<int>::iterator it=c.begin();有没有熟悉的感觉
List<int>::ListIterator lend(b.end());
display(lstart,lend);
return 0;
}
到这里,就基本理解迭代器的实现过程了,以及为什么要有迭代器,它的作用是什么。
下面的代码是STL中的迭代器的使用。
STL迭代器代码示例:
#include "stdafx.h"
#include<iostream>
#include<numeric>
#include<list>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
list<int> c(10);
std::iota(c.begin(),c.end(),1);
list<int>::iterator it=c.begin();//迭代器
for(;it!=c.end();it++)
{
cout<<*it<<" ";
}
return 0;
}
部分STL源码
//链表节点定义
template<class _Value_type,
class _Voidptr>
struct _List_node
{ // list node
_Voidptr _Next; // successor node, or first element if head
_Voidptr _Prev; // predecessor node, or last element if head
_Value_type _Myval; // the stored value, unused if head
private:
_List_node& operator=(const _List_node&);
};