zoukankan      html  css  js  c++  java
  • 迭代器配接器详解

    

    迭代器是一个纯粹的抽象概念:任何东西,只要其行为类似迭代器,它就是一个迭代器。因此,你可以撰写一些类别(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, "
    ");
    	*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

  • 相关阅读:
    C#异步编程由浅入深(一)
    基于Jira的运维发布平台的设计与实现
    kubeadm部署K8S并使用containerd做运行时
    代码阅读
    黑客攻防 1
    Linux 常用指令篇1
    期刊管理系统总结
    docker安装RabbitMQ
    Centos7安装mysql8.0教程
    java动态编译
  • 原文地址:https://www.cnblogs.com/ggzone/p/10121349.html
Copyright © 2011-2022 走看看