STL学习总结之<迭代器>

1 迭代器

迭代器是一种“能够遍历某个序列内的所有元素”的对象。它可以透过与一般指针一致的接口来完成自己的工作。迭代器是一种抽象的概念:任何东西,只要行为类似迭代器,就是一种迭代器。迭代器中“能力”是一个很重要的概念,据此可将迭代器划分成不同的类型。

2 迭代器的类型

迭代器类型

能力

供应者

Input(输入)迭代器

向前读取(read)

istream

Output(输出)迭代器

向前写入(write)

ostream,inserter

Forward迭代器

向前读取和写入

Bidirectional(双向)迭代器

向前和向后读取和写入

list,set,multiset,map,multimap

Random access(随机)迭代器

随机存取,可读取也可写入

vector,deque,string,array

3 Input迭代器

Input迭代器只能一次一个向前读取元素,按此顺序一个个传回元素值。Input的操作行为如下:

表达式

效果

*iter

读取实际元素

iter->member

读取实际元素的成员(如果有的话)

++iter

向前步进(传回新位置)

iter++

向前步进(传回旧位置)

iter1 == iter2

判断两个迭代器是否相等

iter1 != iter2

判断两个迭代器是否不相等

TYPE(iter)

复制迭代器(copy)构造函数

注:

(1) Input迭代器只能读取元素一次,如果复制Input迭代器,并使原Input迭代器和新产生的副本都向前读取,可能会遍历到不同的值(eg3)。几乎所有的迭代器都具备Input迭代器的能力,而且通常更强,纯粹的Input迭代器的一个典型例子是“从标准输入装置读取数据”的迭代器。同一个值不会被读取两次,一旦从输入流读入一个字后(离开input缓冲区),下次读取时就会传回另一个字。

eg1:

View Code
 1 eg1:
 2 #include<iostream>
 3 #include<iterator>
 4 using namespace std;
 5 int main()
 6 {
 7     istream_iterator<int> test(cin);
 8     istream_iterator<int> test2(test);
 9     cout<<*test<<" "<<*test2<<endl;
10     return 0;
11 }
12 输入:2
13 输出:2  2

eg2:

View Code
 1 eg2:
 2 #include<iostream>
 3 #include<iterator>
 4 using namespace std;
 5 int main()
 6 {
 7     istream_iterator<int> test(cin);
 8     istream_iterator<int> test2(test);
 9     ++test;
10     cout<<*test<<" "<<*test2<<endl;
11     return 0;
12 }
13 输入: 2  3  4  5
14 输出: 3  2
15 -------------------------------------------------------------------------

eg3:

View Code
 1 eg3:
 2 #include<iostream>
 3 #include<iterator>
 4 using namespace std;
 5 int main()
 6 {
 7     istream_iterator<int> test(cin);
 8     istream_iterator<int> test2(test);
 9     ++test;
10     ++test2;
11     cout<<*test<<" "<<*test2<<endl;
12     return 0;
13 }
14 输入: 2  3  4  5
15 输出: 3  4

(2) 应该尽可能优先选用前置式递增运算操作符(++iter)而不是后置式(iter++)因为前者有更好的性能。

(3) Input迭代器不支持递减操作符

4 Output迭代器

Output迭代器与Input迭代器相反,其作用是将元素值一个个写入,只能一个一个地赋新值。Output迭代器的操作如下:

表达式

效果

*iter = value

将数值写到迭代器所指位置

++iter

向前步进(传回新位置)

iter++

向前步进(传回旧位置)

TYPE(iter)

复制迭代器(copy构造函数)

注:Output迭代器无需比较操作,无法鉴定Output迭代器是否有效,可做的就是写入、写入再写入。

几乎所有的迭代器都有Output迭代器的功能。纯粹的Output迭代器的一个典型例子就是“将元素写到标准输出装置”的迭代器。如果采用两个Output迭代器写至屏幕,第二个将跟在第一个后面,而不是覆盖第一个字(eg1)。Output的另一个典型的例子是inserters。inserters是将元素插入容器的一种迭代器,如果向它赋予一个新值就是将它安插到容器内。如果写入第二个值,并不会覆盖第一个值,而是将改值安插进去(eg2)。

eg1:

View Code
 1 #include<iostream>
 2 
 3 #include<iterator>
 4 
 5 using namespace std;
 6 
 7  
 8 
 9 int main()
10 
11 {
12 
13          ostream_iterator<int>test1(cout);
14 
15          ostream_iterator<int>test2(test1);
16 
17          cout<<"test1 and test2"<<endl;
18 
19          *test1 = 1;
20 
21          *test2 = 2;
22 
23          cout<<endl;
24 
25          return 0;
26 
27 }
28 
29 输出:
30 
31 test1 and test2
32 
33 12
34 
35 -----------------------------------------------------------------------------

eg2:

View Code
 1 eg2:
 2 
 3 #include<iostream>
 4 
 5 #include<vector>
 6 
 7 #include<iterator>
 8 
 9  
10 
11 using namespace std;
12 
13  
14 
15 void print(vector<int>& ivec)
16 
17 {
18 
19          vector<int>::iterator ibegin=ivec.begin();      
20 
21          for(; ibegin!=ivec.end(); ++ibegin)
22 
23          {
24 
25                    cout<<*ibegin<<" ";
26 
27          }
28 
29          cout<<endl;
30 
31 }
32 
33  
34 
35 int main()
36 
37 {
38 
39          vector<int> ivec;
40 
41          back_insert_iterator<vector<int> > iter(ivec);
42 
43          *iter = 1;
44 
45          print(ivec);
46 
47          *iter = 2;
48 
49          print(ivec);
50 
51          return 0;
52 
53 }
54 
55 输出:
56 
57 1
58 
59 1  2

5 Forward(前向)迭代器

Forward迭代器是Input迭代器和Output迭代器的结合,具有Input迭代器的全部功能和Output迭代器的大部分功能。Forward迭代器的所有操作如下:

表达式

效果

*iter

存取实际元素

iter->member

存取实际元素成员

++iter

向前步进

iter++

向前步进

iter1 == iter2

判断两迭代器是否相等

iter1 != iter2

判断两个迭代器是否不等

TYPE()

产生迭代器(default构造函数)

TYPE(iter)

复制迭代器(copy构造函数)

iter1 = iter2

赋值

和Input迭代器及Output迭代器不同,Forward迭代器能多次指向同一个群集中的同一元素,并能多次处理同一元素。

Output迭代器在写入元素时不用有末端检查,Forward迭代器在存取元素时必须要有末端检查,防止未定义行为的发生。

6 Bidirectional(双向)迭代器

Bidirectional迭代器在Forward迭代器的基础上增加了回头遍历的能力,它支持递减运算操作符,用以一步一步的后退操作。Bidirectional迭代器新增的操作如下:

算式

效果

--iter

步退(传回新位置)

iter--

步退(传回旧位置)

7 Random Access(随机存取)迭代器

Random Access迭代器在Bidirectional迭代器的基础之上再增加随机存取能力。因此它必须提供“迭代器算术运算”。它能加减某个偏移量、能处理距离问题,并运用关系运算符进行比较。Random Access迭代器的新增操作。

算式

效果

iter[n]

存取索引位置为n的元素

iter+=n

向前跳n个元素(如果n是负数,则向后跳)

iter-n

向后跳n个元素(如果n是负数,则向前跳)

iter+n/n+iter

传回iter之后的第n个元素

iter-n

传回iter之前的第n个元素

iter1-iter2

传回iter1和iter2之间的距离

iter1 < iter2

判断iter1是否在iter2之前

iter1 > iter2

判断iter1是否在iter2之后

iter1<= iter2

判断iter1是否不在iter2之后

iter1 >= iter2

判断iter1是否不在iter2之前

8关于Vectorstrings迭代器的递增和递减问题

为了保证可移植性,最好不要递增或递减暂时性迭代器,如:sort(++coll.begin(),coll.end());因为,如果迭代器被实作为一般指针则编译会失败,C++不允许修改任何基本型别(包括指针)的暂时值(eg1)。

eg1:

View Code
 1 eg1:
 2 
 3 #include<iostream>
 4 
 5 using namespace std;
 6 
 7 class Test
 8 
 9 {
10 
11 private:
12 
13          int num;
14 
15 public:
16 
17          Test():num(0){}
18 
19          Test& operator ++()
20 
21          {
22 
23                    ++num;
24 
25                    return *this;
26 
27          }
28 
29          friend ostream& operator <<(ostream& out, const Test& test);
30 
31 };
32 
33 int func1()
34 
35 {
36 
37          int a = 5;
38 
39          return a;
40 
41 }
42 
43 int* func2()
44 
45 {
46 
47          int a = 5;
48 
49          return &a;  //E(返回局部变量的地址)
50 
51 }
52 
53  
54 
55 Test func3()
56 
57 {
58 
59          Test test;
60 
61          return test;
62 
63 }
64 
65 ostream& operator <<(ostream& out, const Test& test)
66 
67 {
68 
69          out << test.num;
70 
71 }
72 
73 int main()
74 
75 {
76 
77          cout<<++func1()<<endl;  //A(修改基本型别的临时变量的值)
78 
79          cout<<++func2()<<endl;  //B(修改指针类型的临时变量的值)
80 
81          cout<<++func3()<<endl;  //C(修改自定义型别的临时变量的值)
82 
83          cout<<++(*func2())<<endl;  //D(对临时变量解引用并改变其值)
84 
85  
86 
87          return 0;
88 
89 }

编译结果:

A和B处会报告错误:“++”需要左值。C处不会报错。D处不会报错,因为解引用和下标操作符都会返回左值。E处会有警告:返回局部变量或临时变量地址。

9 迭代器辅助函数

9.1 advance()
advance()可将迭代器的位置增加,增加的幅度由参数决定,也就是使迭代器一次前进(或后退)多个元素。

#include <iterator>

void advance(InputIterator& pos, Dist n)

使名为pos的Input迭代器步进(或步退)n个元素。对Bidirectional迭代器和RandomAccess迭代器而言,n可为负值,表示向后退,对于输入迭代器和输出迭代器n为负数时无操作或行为未定义(eg1)。注:advance()并不检查迭代器是否超过end().

eg1:

View Code
 1 eg1:
 2 
 3 #include<iostream>
 4 
 5 #include<iterator>
 6 
 7 using namespace std;
 8 
 9  
10 
11 int main()
12 
13 {
14 
15          istream_iterator<int>test(cin);
16 
17          cout<<"please input at least 3 nums"<<endl;
18 
19          cout<<"first: "<<*test<<endl;
20 
21          advance(test,2);
22 
23          cout<<"third: "<<*test<<endl;
24 
25          advance(test,-1);
26 
27          cout<<"second: "<<*test<<endl;
28 
29          return 0;
30 
31 }
32 
33 在VS2010下输出:
34 
35 please input at least 3 nums
36 
37 first: 1
38 
39 third: 3
40 
41 second: 3
42 
43 ------------------------------------------------------------------------

9.2 distance()

函数distance()可以用来处理两个迭代器之间的距离:

#include<iterator>

Dist  distance(InputIterator  pos1, InputIterator  pos2)

注:

(1)传回两个Input迭代器pos1和pos2之间的距离。

(2)两个迭代器都必须指向同一个容器

(3)如果不是RandomAccess迭代器,则从pos1开始往前走必须能够到达pos2,也就是说pos2的位置必须与pos1相同或在其后。

(4)返回值Dist的型别由迭代器决定:

iterator_traits<InputIterator>::difference_type

对于non_RandomAccess迭代器而言distance()的性能并不好,应尽力避免,如果想在程序中轻松更换容器型别和迭代器型别,应该用distance();

9.3 iter_swap()

iter_swap()用来交换两个迭代器所指的元素值。

#include<algorithm>

void iter_swap(ForwardIterator1 pos1, ForwardIterator2 pos2)

注:

(1)交换迭代器pos1和pos2所指的值。

(2)迭代器的型别不必相同,但其所指的两个值必须可以相互赋值。

10 迭代器配接器

10.1 Reverse(逆向)迭代器

Reverse迭代器是一种配接器,重新定义递增运算和递减运算,使其行为正好倒置。如果使用这种迭代器,算法将以逆向次序来处理元素。所有标准容器都允许用Reverse迭代器来遍历元素。如:

vector<int> coll;

for_each(coll.begin(),coll.end(),print);//正向

for_each(coll.rbegin(),coll.rend(),print);//逆向

10.2迭代器和Reverse迭代器

可以将一般迭代器转化成一个Reverse迭代器,只要原来的迭代器具有双向移动能力。注意,转换后迭代器的逻辑位置发生了变化(Reverse迭代器的所指实际位置与逻辑位置不同,逻辑位置是实际所指位置的下一个位置),而迭代器实际所指的位置并没有变化(eg1)。

eg1:

View Code
 1 eg1:
 2 
 3 #include<iostream>
 4 
 5 #include<vector>
 6 
 7 #include<algorithm>
 8 
 9 using namespace std;
10 
11 int main()
12 
13 {
14 
15          vector<int> coll;
16 
17          for(int i=1; i<=9; ++i)
18 
19          {
20 
21                    coll.push_back(i);
22 
23          }
24 
25          vector<int>::iterator pos;
26 
27          pos = find(coll.begin(),coll.end(),5);
28 
29          cout<<"pos: "<<*pos<<endl;
30 
31          vector<int>::reverse_iterator rpos(pos);
32 
33          cout<<"rpos: "<<*rpos<<endl;
34 
35          return 0;
36 
37 }
38 
39 输出:
40 
41 pos: 5
42 
43 rpos: 4

注:pos与rpos所指位置相同,但rpos的逻辑值,即实际要输出的值是4。因为rpos逻辑要输出的值就是4。因为pos离begin()的距离是4,则rpos离rend()的距离也应该是4,而rend()实际所指位置为begin()位置,所以rend()的逻辑位置为begin()的前一个位置,故Reverse迭代器的逻辑位置位于实际位置的前一个位置。(详见《C++标准程序库》中文版P267)

base()函数

base()函数可以将逆向迭代器转换成正常迭代器。像转换为逆向迭代器一样,实际位置维持不动,变化的是逻辑位置。

10.2 Insert(安插型)迭代器

Insert迭代器用来将“赋值新值”操作转换为“安插新值”操作。通过这种迭代器,算法可以执行安插操作,所有的Insert迭代器都隶属于Output迭代器类型。

注:

(1)operator *被实作为一个无实际动作的动作,只是简单地传回*this,所以对于Insert迭代器来说,*pos与pos等价。

(2)赋值操作转化安插操作(eg1)。

(3)递增运算也被实作为一个no-op,也是简单地传回一个*this(eg1)。

eg1:

vector<int> coll;

back_insert_iterator<vector<int> >iter(coll);

*iter = 1;//A

++iter;//可有可无

iter = 2;//B与A等价

---------------------------------------------

Insert迭代器的操作

算式

效果

*iter

无实际操作

iter=value

安插value

++iter

无实际操作(传回iter)

iter++

无实际操作(传回iter)

Insert迭代器的种类

C++标准程序库提供三种Insert迭代器:back inserts, front inserts, general inserts.它们之间的区别在于插入位置,不同的迭代器适用的容器类型存在一些差异,在Insert迭代器初始化时一定要清楚自己所属的容器是哪一种,是否支持对应操作。每一种Insert迭代器都可以由一个对应的便捷函数加以生成和初始化。Insert迭代器的种类如下:

名称

Class

其所调用的函数

便捷生成函数

Back inserter

back_insert_iterator

push_back(value)

back_inserter(cont)

Front inserter

front_insert_iterator

push_front(value)

front_inserter(cont)

General inserter

insert_iterator

insert(pos,value)

inserter(cont)

10.2.1 BackInserters

Back inserters透过成员函数push_back()将一个元素追加到容器尾部。支持的容器有:vector,deque,list,string.

使用方法:

(1) 根据所属容器初始化使用

vector<int> coll;

back_insert_iterator<vector<int> > iter(coll);

*iter=1;//插入元素。

copy(coll.begin(),coll.end(),iter);

(2)利用back_inserter

vector<int>coll;

back_inserter(coll)=3;

copy(coll.begin(),coll.end(),back_inserter(coll));

10.2.2 Front Inserters

Front inserters透过成员函数push_front将一个元素值加在容器头部。支持的容器有:deque和list。

使用方法:

(1)根据所属容器初始化使用

list<int> coll;

front_insert_iterator<list<int> > iter(coll);

*iter=1;

copy(coll.begin(),coll.end(),iter);

(2)利用front_inserter

list<int>coll;

front_inserter(coll)=3;

copy(coll.begin(),coll.end(),front_inserter(coll));

10.2.3 General Inserters

General Inserter根据两个参数而初始化:容器和待安插位置。迭代器内部以待安插位置为参数,调用成员函数insert().General Inserter对所有标准容器都适用,因为所有容器都有insert()成员函数,对于关联式容器,安插位置只是个提示,因为在这两个容器中元素的真正位置视其键值而定。安插完毕后general inserter获得刚刚被安插的那个元素的位置。

使用方法:

(1) 根据使用容器初始化和位置

set<int> coll;

insert_iterator<set<int> >iter(coll,coll.begin());

*iter=1;

copy(coll.begin(),coll.end(),iter);

(2)利用inserter

set<int>coll;

set<int>coll2;

inserter(coll,coll.end())=3;

copy(coll.begin(),coll.end(),inserter(coll2,++coll2.begin());

10.2.4 Stream(流)迭代器

stream迭代器是一种迭代器配接器,通过它可以把stream当成算法的原点和终点,一个istream迭代器可用来从input stream中读取元素,而一个ostream迭代器可以用来对output stream写入元素。

Ostream迭代器

ostream迭代器可以将赋予的值写入output stream中,ostream迭代器将赋值操作转化为operator <<。ostream迭代器的各项操作如下:

算式

效果

ostream_iterator<T>(ostream)

为ostream产生一个ostream迭代器

ostream_iterator<T>(ostream,delim)

为ostream产生一个ostream迭代器,各个元素间以delim为分隔符(delim的类型为const char*)

*iter

无实际操作,传回iter

iter=value

将value写到

ostream(ostream<<value<<delim)

++iter

无实际操作,传回iter

iter++

无实际操作,传回iter

注:产生ostream迭代器时,必须提供一个output stream作为参数,迭代器将会把元素值写到该output stream身上,另一个参数可有可无,是个字符串,被用来作为每一个元素值之间的分隔符。

使用方法:

ostream_iterator<int> intWriter(cout,"\n");

*intWriter = 42;//输出42和换行

intWriter++;//无实际操作。

vector<int>coll;

copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));

Istream

istream迭代器用来从input stream读取元素,透过istream迭代器,算法可以从stream中直接读取数据。产生istream迭代器时必须提供一个input stream作为参数,迭代器将从其中读取数据。为例确定读取是否已经到了总点,可以使用一个end-of-stream迭代器,只要有任何一次失败,所有istream迭代器都会变成end-of-stream迭代器,所以每进行一次读取都要和end-of-stream进行一次读取,看看当前迭代器是否仍然合法。istream迭代器的各项操作如下:

算式

效果

istream_iterator<T>()

产生一个end-of-stream迭代器

istream_iterator<T>(istream)

为istream产生一个迭代器

*iter

传回先前读取的值或执行读取任务

iter->member

传回先前读取元素的成员

++iter

读取下一个元素,并传回其位置

iter++

读取下一个元素,并传回迭代器指向前一个元素

iter1==iter2

检查iter1和iter2是否相等

iter1!=iter2

检查iter1和iter2是否不相等

使用方法:

eg1:

istream_iterator<int> intReader(cin);

istream_iterator<int> intReaderEOF;

while(intReader != intReadEOF)

{

         cout<<"once: "<<*intReader<<endl;

         cout<<"again: "<<*intReader<<endl;

         ++intReader;

}

输入:

1 2 3 f 4

输出:

once: 1

again: 1

once: 2

again: 2

once: 3

again: 3

---------------------------------------------------------------

eg2:

istream_iterator<string>cinPos(cin);

ostream_iterator<string>coutPos(cout);

while(cinPos != istream_iterator<string>())

{   *coutPos++ = *cinPos++;  }

cout<<endl;

----------------------------------------------------------------

原文地址:https://www.cnblogs.com/landy126/p/2943055.html