iterator的好处
template<class P,class T>
P find(P start,P beyond,const T& x)
{
while( start != beyond && * start != x)
++start;
return start;
}
template<class P, class T>
void reverse(P start, P beyond)
{
while(start != beyond) {
--beyond;
if (start != beyond) {
T t = *start;
*start = *beyond;
*beyond = t;
++ start;
}
}
}
我们可以看到,这两个函数都对模板参数P做了一定要求,在find中,我们要求P必须允许 != ,++和(P)这三个运算符的操作,而对于reverse函数来说,其要求更多,运算符++,–,(),!=都必须支持.问题就这么出来了,我们怎么让所有人都遵守这一要求呢?或者说,后续采用这个模板的使用者怎么能在不知道实现细节的情况下了解并遵守这些要求呢?显然,我们需要一个分类方法来知道如何界定不同种类的迭代器.
不过这里还是没有解释一个疑惑,即这两个函数改成T的指针也能完成的很好,我们还要iterator做什么?
答案很简单,不是所有数据结构都是线性的!对于一个链表来说,如果要实现上述的功能,我们必须重新写一个几乎一样仅仅是把++start变成start = start->next的函数.显然,这样重复的事情我们是不希望碰到的,尤其如果函数还非常大的情况下.而这时候,iterator的作用就出来了.对于链表,我们的链表的iterator(list_iterator)仅仅只要把operator++()重写成operator++(){now = now->next;},就能正常的使用find函数了.完全不需要重新编写.这就减少了我们算法的编写量.
现在,既然我们知道了iterator的好处了之后,接下来我们就想知道之前提到的分类法是怎么回事了.经常听说输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机存取迭代器是怎么回事.
iterator的分类
迭代器的分类:
1.输入迭代器(input iterator)
```input iterator就像其名字所说的,工作的就像输入流一样.我们必须能
取出其所指向的值
访问下一个元素
判断是否到达了最后一个元素
可以复制
因此其支持的操作符有 *p,(++p,p++),p->,p!=q,p == q这五个.凡是支持这五个操作的类都可以称作是输入迭代器.当然指针是符合的.
```
2.输出迭代器(output iterator)
output iterator工作方式类似输出流,我们能对其指向的序列进行写操作,其与input iterator不相同的就是*p所返回的值允许修改,而不一定要读取,而input只允许读取,不允许修改.
支持的操作是 *p,++p,p++,p = q. 其解引用操作(*) 的结果只能作为左值使用.
使用Input iterator和output iterator的例子:
template<class In,class Out>
void copy(In start,In beyond, Out result)
{
while(start != beyond) {
*result = *start; //result是输出迭代器,其*result返回的值允许修改
++result;
++start;
}
}
//简写
template<class In,class Out>
void copy(In start,In beyond, Out result)
{
while(start != beyond)
*result++ = *start++;//这个应该能看懂的...
}
3.前向迭代器(forward iterator)
前向迭代器就像是输入和输出迭代器的结合体,其*p既可以访问元素,也可以修改元素.因此支持的操作也是相同的.
4.双向迭代器(bidirectional iterator)
双向迭代器在前向迭代器上更近一步,其要求该种迭代器支持operator–,因此其支持的操作有 *p,++p,p++,p!=q,p == q,–p,p–
5. 随机存取迭代器(random access iterator)
即如其名字所显示的一样,其在双向迭代器的功能上,允许随机访问序列的任意值.显然,指针就是这样的一个迭代器.
对于随机存取迭代器来说, 其要求高了很多:
可以判断是否到结尾( a==b or a != b)
可以双向递增或递减( –a or ++a)
可以比较大小( a < b or a > b or a>=b …etc)
支持算术运算( a + n)
支持随机访问( a[n] )
支持复合运算( a+= n)
上面即为我们所讨论到的几个迭代器的层次.看起来很像继承是麽?
但是实际上在STL中,这些并不是通过继承关联的.这些只不过是一些符合条件的集合.这样的好处是:少去了一个特殊的基类(input iterator),其次,使得内建类型指针可以成为iterator.
其实只要明白iterator是满足某些特别的功能的集合(包括类和内建类型),就不会觉得是继承了.
Iterator使用:
一个ostream_iteartor的例子:
#include <iostream>
#include <vector>
using namespace std;
template<class T>
class Ostream_iterator {
public:
Ostream_iterator(ostream &os,const char* s):
strm(&os), str(s){}
Ostream_iterator& operator++() {return *this;}
Ostream_iterator& operator++(int) {return *this;}
Ostream_iterator& operator*() {return *this;}
Ostream_iterator& operator=(const T& t)
{
*strm << t << str;
return *this;
}
private:
ostream* strm;
const char *str;
};
template<class In,class Out>
Out Copy(In start,In beyond,Out dest)
{
while(start != beyond)
*dest++ = *start++;
return dest;
}
int main()
{
Ostream_iterator<int> oi(cout, " ");
int a[10];
for (int i = 0;i!=10;++i)
a[i] = i+1;
vector<int>v(a,a+10);
Copy(v.begin(),v.end(),oi);
return 0;
}
第二个例子关于input iterator这里有空再看。
http://www.cnblogs.com/marchtea/archive/2012/02/27/2370068.html
主要有
1: 堆排序
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
int a[] = {12,3,2,3,12};
vector<int>v(a,a+5);
sort_heap(v.begin(),v.end()); //好奇怪的名字
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
}#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
int a[] = {12,3,2,3,12};
vector<int>v(a,a+5);
sort_heap(v.begin(),v.end()); //好奇怪的名字
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
}
1.2 指定位置的排序n_th element
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
int a[] = {2,1,0,4,3,7,5,6};
vector<int>v(a,a+8);
nth_element(v.begin(),v.begin()+4,v.end()); //好奇怪的名字
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
cout<<endl;
nth_element(v.begin(),v.begin(),v.end()); //好奇怪的名字
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
}
2:transform函数
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
double doubleIt(int i)
{
return 2*i;
}
void printIt(int i)
{
cout<<i<<" "<<endl;
}
void foo(int *a, int *b)
{
cout<<*a<<endl;
}
int main()
{
vector<int>v1,v2;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v2.resize(3);
transform(v1.begin(),v1.end(),v2.begin(),doubleIt); //改变容器的算法
for_each(v1.begin(),v1.end(),printIt); //printIt是这样用的,不能修改容器.
//foo(v1.begin(),v1.end()); //证明了不是这么容易写出来的.
//ostream_iterator<int>
copy(v2.begin(),v2.end(),ostream_iterator<int>(cout," "));
}
3 STL partial_sort函数
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
int main()
{
int a [] = {32,1,21,-12,434};
vector<int> v(a,a+5);
partial_sort(v.begin(),v.begin()+3,v.end()); //部分排序.
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
}
4 STL heap相关函数
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
int a[] = {2,1,0,4,3,7,5,6};
vector<int>v(a,a+8);
make_heap(v.begin(),v.end()); //greater or less?
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
cout<<endl;
pop_heap(v.begin(),v.end());
v.pop_back();//必须加上这一步,因为pop_heap把堆顶元素取出来,放到了数组或者是vector的末尾,用原来末尾元素去替代,
//并没有删除
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
cout<<endl;
v.push_back(12);
push_heap(v.begin(),v.end());
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
cout<<endl;
}