导航

迭代器配接器详解

Posted on 2014-07-21 17:57  ggzone  阅读(166)  评论(0编辑  收藏  举报


迭代器是一个纯粹的抽象概念:任何东西,只要其行为类似迭代器,它就是一个迭代器。因此,你可以撰写一些类别(classes),具备迭代器接口,但有着各不相同的行为。C++标准程序库提供了数个预先定义的特殊迭代器,亦即所谓迭代器配接器(iterator adapters)。它们不仅起辅助作用,还能赋予整个迭代器抽象概念更强大的能力。
     1、Insert iterators (安插型迭代器)
     2、Stream iterators (流迭代器)
     3、Reverse iterators (逆向迭代器)


Stream iterators

Stream迭代器是一种迭代器配接器,通过它,你可以把stream当成算法的原点和终点。更明确的说,一个istream迭代器可以用来从input stream中读元素,而一个ostream迭代器可以用来对output stream写入元素。Stream迭代器的一种特殊形式是所谓的stream缓冲区迭代器,用来对stream缓冲区进行直接读取和写入操作。

Ostream迭代器可以被赋予的值写入output stream中。下表列出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

#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>

using namespace std;

int main()
{
	
	ostream_iterator<int> intWriter(cout, "\n");
	*intWriter = 43;
	intWriter++;//无实际操作
	*intWriter = 77;
	intWriter = -5;

	vector<int> coll;
	for (int i = 1; i <= 9; ++i)
	{
		coll.push_back(i);
	}
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;
	system("pause");
}


输出:

43
77
-5
1 2 3 4 5 6 7 8 9



istream迭代器是ostream迭代器的拍档,用来从input stream读取元素。透过istream迭代器,算法可以从stream中直接读取数据。istream迭代器的各项操作。产生一个istream迭代器时,必须提供一个input stream作为参数,迭代器从中读取数据。然后它便经由input迭代器的一般接口,利用operator<<读取数据。然而,读取动作有可能失败(可能到达文件尾部,或读取错误),此外算法也要知道区间是否到达终点。为解决这些问题,可以使用一个end_of_stream迭代器,可以利用默认构造函数生成。只要有任何一次读取失败,所有istream迭代器都会变成end_of_stream迭代器,所以进行一次读取后, 应该将istream迭代器和end_of_stream迭代器比较一番。

算式

效果

istream_iterator<T>()

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

istream_iterator<T>(istream)

istream产生的一个迭代器(可能立即去读第一个元素)

*iter

传回先前读取的值(如果构造函数并未立刻读取第一个元素值,则本式执行读取任务)

iter->member

传回先前读取的元素的成员(如果有的话)

++iter

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

iter++

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

iter1 == iter2

检查iter1iter2是否相等

iter1 != iter2

检查iter1iter2是否不相等

注意:istream迭代器的构造函数会打开stream,读取第一个元素。所以,不要过早定义它。如果满足一下条件我们说两个istream迭代器相等:

两者都是end_of_stream迭代器

两者都可以再进行读取操作(未变为end_of_stream迭代器),并指向相同的stream。

#include<iostream>
#include<iterator>

using namespace std;

int main()
{
	
	istream_iterator<int> intReader(cin);
	istream_iterator<int> intReaderEOF;
	while (intReader != intReaderEOF)
	{
		cout << "once:" << *intReader << endl;
		cout << "once again:" << *intReader << endl;
		++intReader;
	}

	system("pause");
}

输出:字符f导致程序结束。

1 2 3 f 4
once:1
once again:1
once:2
once again:2
once:3
once again:3


Stream迭代器的另一个例子:

#include<iostream>
#include<iterator>
#include<string>
#include<algorithm>

using namespace std;

int main()
{
	
	istream_iterator<string> cinPos(cin);
	ostream_iterator<string> coutPos(cout, " ");
	istream_iterator<string> intReaderEOF;
	while (cinPos != intReaderEOF)
	{
		advance(cinPos, 2);
		if (cinPos != intReaderEOF)//跳过两个位置后是否到达end_of_stream
		{
			*coutPos++= *cinPos++;
		}
	}
	cout << endl;
	system("pause");
}

输入:

No one objects if you are doing a good programming job for someone who you respe
ct.

输出:
objects are good for you


Reverse Iterators

逆向迭代器重新定义递增运算和递减运算,使其行为正好倒置。

deque<int>::iterator pos1,pos2;//coll元素:1,2,3,4……9
pos1=find(coll.begin(),coll.end(),2);
pos2=find(coll.begin(),coll.end(),7);
for_each(pos1,pos2,print);     //输出:2 3 4 5 6

deque<int>::reverse_iterator rpos1(pos1);
deque<int>::reverse_iterator rpos2(pos2);
for_each(rpos2,rpos1,print);    //输出:6 5 4 3 2

迭代器pos1和pos2定义了一个半开区间,包括2不包括7。当把描述这一区间的两个迭代器转换为Reverse迭代器时,该区间仍然有效,而且可以被逆序处理。

将迭代器转换为逆向迭代器:container::reverse_iterator(it);//it为迭代器

将逆向迭代器转换回来:rpos.base();//rpos为逆向迭代器


Insert iterators

Insert迭代器,也称为inserters,用来将“赋值新值”操作转换为“安插新值”操作。通过这种迭代器,算法可以执行安插(insert)行为而非覆盖(overwrite)行为。所有Insert迭代器都隶属于Output迭代器类型,所以它只提供赋值(assign)新值的能力。通常算法会将数值赋值给目的迭代器,如copy()算法

namespace std{
template<class Inputiterator,class Outiterator,Outputiterator>
Outputiterator copy(Inputiterator from_pos,Inputiterator from_end,Outputiterator to_pos)
{
   while(from_pos!=from_end)
   {
      *to_pos=*from_pos;
      ++from_pos;
      ++to_pos;
   }
}
}

*to_pos=*from_pos;

insert迭代器可以把上述这样的赋值转化为安插操作。不过实际上里面有两个操作:首先operator*传回迭代器当前位置(为何不是值,看下面表),然后再由operator=赋值新值,即安插操作。注意:

1、operator*被视作一个无实际动作的动作(no-op),简单返回一个*this,对于insert迭代器来说,*pos与pos等价。

2、赋值动作被转化为安插操作,事实上insert迭代器会调用push_back(),push_front()或insert()成员函数。

下表列出Insert迭代器的所有操作函数。

表达式

效果

*iter

无实际操作(传回iter

iter = value

安插value

++iter

无实际操作(传回iter

iter++

无实际操作(传回iter

C++标准程序库提供三种Insert迭代器:back inserters, front inserters, general inserters。它们的区别在于插入位置。事实上它们各自调用所属容器中不同的成员函数。所以Insert迭代器初始化时要清楚知道自己所属的容器是哪一种。每一种insert迭代器都可以由一个对应的便捷函数加以生成和初始化。下表列出不同的insert迭代器及其能力。

名称

Class

其所调用的函数

便捷函数

Back inserter

back_inserter_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, pos)

back inserters(安插于容器最尾端),内部调用push_back(),在容器尾端插入元素。只有支持push_back()的vector、deque、list、string可以使用Back inserters。

#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>

using namespace std;

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

	iter = 1;
	*iter = 2;//等价iter=1
	++iter;//无实际操作
	iter++;//无实际操作
	iter = 3;
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	back_inserter(coll) = 44;
	back_inserter(coll) = 45;
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	coll.reserve(2 * coll.size());
	copy(coll.begin(), coll.end(), back_inserter(coll));
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	system("pause");
}

注意,一定要在调用copy()之前确保有足够大的空间,因为back inserter在安插元素时,可能会造成指向该vector的其它迭代器失效。

输出:

1 2 3
1 2 3 44 45
1 2 3 44 45 1 2 3 44 45


Front inserters(安插于容器最前端),内部调用push_front(),在容器前端插入元素。只有支持push_front()的deque、list可以使用Front inserters。

#include<iostream>
#include<list>
#include<algorithm>
#include<iterator>

using namespace std;

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

	iter = 1;
	*iter = 2;//等价iter=1
	++iter;//无实际操作
	iter++;//无实际操作
	iter = 3;
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	front_inserter(coll) = 44;
	front_inserter(coll) = 45;
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

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

	system("pause");
}

输出:

3 2 1
45 44 3 2 1
1 2 3 44 45 45 44 3 2 1


General inserters(一般性安插器),内部调用insert(),将元素插入到pos所指位置的前方。所有STL容器都提供insert()成员函数,所以这是唯一可用于关联式容器的预定义inserter。根据两个参数初始化:容器和待安插位置。安插操作完成后,General inserters获得刚刚被安插的那个元素的位置,实际上相当于以下语句:

pos=container.insert(pos,value);
++pos;
然后新获得的位置再下次安插时使用。

#include<iostream>
#include<set>
#include<list>
#include<algorithm>
#include<iterator>

using namespace std;

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

	iter = 1;
	*iter = 2;//等价iter=1
	++iter;//无实际操作
	iter++;//无实际操作
	iter = 3;
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	inserter(coll, coll.begin()) = 44;
	inserter(coll, coll.begin()) = 45;
	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	list<int> coll2;
	copy(coll.begin(), coll.end(), inserter(coll2,coll2.begin()));
	copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	copy(coll.begin(), coll.end(), inserter(coll2, ++coll2.begin()));
	copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;
	system("pause");
}

输出:

1 2 3
1 2 3 44 45
1 2 3 44 45
1 1 2 3 44 45 2 3 44 45