经过前面对各容器的讲解,相信大家已经对迭代器有一定的了解了,迭代器作为STL中的几大模块之一(系统工具,容器,迭代器,算法,仿函数,string以及iostream),重要性毋庸置疑,现在我们来详细的讨论分析STL中迭代器的用法。
迭代器产生动机:
在早期STL 的实现中,容器和算法是合并在一起的,即每个容器都有他的专属算法,但是后来发现这样效率不高,而且每个容器的很多算法都是大致相同的,于是STL的设计者萌生了把算法和容器分开的想法,即算法只写一次,每个容器都可以调用。从而需要在容器和算法之间需要一个中间变量充当桥梁,由此,迭代器应运而生了。
请注意,上面的图表关系并不代表继承关系,只是下面是上面的扩充集
(因为STL中的迭代器现在只用最后两种,前三种只做简单介绍)
Input_iterator (输入迭代器):输入迭代器只能向前一步一步向前读取元素,而且一个位置只能读一次。
Output_iterator(输出迭代器):输出迭代器只能用来向前一步一步写入元素,一个位置只能写入一次。
Forward_iterator(前向迭代器):前向迭代器基本能做输入输出迭代器可以做的一切事情,既可以读取,也可以写入,而且还可以多次,但是没变的是也只能一步一步的向前,不可跨越。
Bidirectional iterators(双向迭代器):双向迭代器在前向迭代器的基础上做了修改,增加了后退的操作,所以叫双向,同时也保存了前向迭代器的一切特性,但是也只能一步一步的操作,不可跨越,支持他的容器有List set multiset map multimap 。
注意:双向迭代器本身只能支持++ —— != == 操作,不能如下这样使用:
List<int> coll;
List<int>::iterator it;
For(it=coll.begin();it<coll.end();it+1) //error
```````````````````````````````````````
第一个错误在于it<coll.end();双向迭代器不支持<操作符。
第二个错误在于 it+1;双向迭代器只能it++。
所以必须这样写:
For(it=coll.begin();it!=coll.end();it++)
其实也不能想像,在list是由链表实现的,链表访问任何一个位置的元素都只能从表头依次读取下去,不能直接访问那个元素,其他几个容器类似。
Random access iterators(随机存取迭代器):
随机存取迭代器在双向迭代器的基础上在增加了随机存取的能力,他可以增加某个偏移量或减去某偏移量,能处理距离的问题并运用< >运算符,也可以像数组一样随机的访问或者修改某个元素,是现在迭代器的最高进化版本。如果把上面那个错误例子的list改为vector,那就正确。随机存取迭代器跟一般的指针支持的运算一致。他支持的容器是vector deque..
迭代器几个相关辅助函数:
1:advance() 可令迭代器前进或者后退指定的位。
template<class InIt, class Dist>
void advance(InIt& it, Dist n);
第一个参数是传入迭代器,第二个参数一般是整数,如果为正,则表示前进n位,反之则后退n位。(注意在迭代器中往后走代表前进,往前走代表后退)
2:distance() 可以处理两个迭代器之间的位置。
template<class Init, class Dist>
ptrdiff_t distance(InIt first, InIt last);
该函数传入两个迭代器,返回他们相隔的距离,但是务必保证两个迭代器一定要是同一个容器上的,否则导致未定义行为。
3:iter_swap 可以交换两个迭代器所指的的值(迭代器位置不变)
template<class FwdIt1, class FwdIt2>
void iter_swap(FwdIt1 x, FwdIt2 y);
两个参数为两个迭代器,执行完后所指的值被交换。
相信到这里,大家也许会疑惑,随机存储迭代器可以直接相减求距离,也可以直接相加,也可直接交换,那为什么还要这几个函数,其实这几个函数主要是为非随机存取迭代器服务的,因为他们本身不具有这些功能,当他们用于随机存取迭代器,执行的跟我们自己操作的一样,具有常数复杂度,用于双向迭代器的具有对数复杂度。
下面我们针对前面所讲的举一个简单的例子:
#include<iostream>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main()
{
vector<int> vec;
list<int> lis;
for(int by=1;by<21;++by)
{
vec.push_back(by);
lis.push_back(by);
}
vector<int>::iterator it1,it2;
list<int>::iterator io1,io2;
cout<<"对于distance()的用法:"<<endl;
it1=find(vec.begin(),vec.end(),3);
io1=find(lis.begin(),lis.end(),3);
it2=find(vec.begin(),vec.end(),13);
io2=find(lis.begin(),lis.end(),13);
cout<<"vector中的相距位置:"<<(it2-it1)<<endl;
cout<<"list中的相距位置:"<<distance(io1,io2)<<endl<<endl;
cout<<"对于advance()的用法:"<<endl;
cout<<"vector中的相距位置:"<<(it2+3)-(it1+2)<<endl;
advance(io1,2);
advance(io2,3);
cout<<"list中的相距位置:"<<distance(io1,io2)<<endl<<endl;
cout<<"对于iter_swap()的用法:"<<endl;
cout<<"在vector中利用中间变量交换"<<endl;
int mid;
mid=*(it1+2);
*(it1+2)=*(it2+3);
*(it2+3)=mid;
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
cout<<"在list中利用iter_swap()交换:"<<endl;
iter_swap(io1,io2);
copy(lis.begin(),lis.end(),ostream_iterator<int>(cout," "));
cout<<endl;
system("pause");
return 0;
}
对于这个例子,其实就是分别存储1到20的数字在两个不同类型的容器中(当然这里主要是指他们的不同迭代器)。然后分别找到3和13的迭代器位置,vector中可以直接相减得出距离,list只能用distance函数,分别偏移相同的单位,在算出距离。最后交换迭代器所指的内容,很明显16和5的位置改变了。
这个小程序很简单,但是他所体现出来的两种迭代器的不同点却是显然的,一般迭代器辅助函数我们都只对双向迭代器使用,因为随机存取迭代器没必要,但是也要看实际情况而定!讲到这里,主要问题就是理解随机存取迭代器和双向迭代器的区别,关于他们更多的区别,在算法中还会提到。