C++ Primer 学习笔记_43_STL实践与分析(17)(一)

2014-11-24 12:10:33 · 作者: · 浏览: 0

STL实践与分析

--再谈迭代器【中】


二、iostream迭代【续】

3、ostream_iterator对象和ostream_iterator对象的使用

可以使用ostream_iterator对象将一个值序列写入流中,其操作过程与使用迭代器将一组值逐个赋值给容器中的元素相同:

    ostream_iterator
  
    out_iter(cout,"\n");
    istream_iterator
   
     in_iter(cin),eof; while (in_iter != eof) { *out_iter++ = *in_iter++; } 
   
  

读取cin,并将每个读入的值依次写入到cout中不同的行中。

4、在类类型上使用istream_iterator

提供了输入操作符>>任何类型都可以创建istream_iterator对象。

    istream_iterator
  
    item_iter(cin),eof;
    Sales_item sum;
    sum = *item_iter ++;

    while (item_iter != eof)
    {
        if (item_iter -> same_isbn(sum))
        {
            sum += *item_iter;
        }
        else
        {
            cout << sum << endl;
            sum = *item_iter;
        }
        ++ item_iter;
    }
    cout << sum << endl;

  

5、流迭代器的限制

1)不可能从ostream_iterator对象读入,也不可能写到istream_iterator对象中。

2)一旦给ostream_iterator对象赋了一个值,写入就提交了。赋值后,没有办法再改变这个值。此外,ostream_iterator对象中每个不同的值都只能正好输出一次。

3)ostream_iterator没有 ->操作符。

6、与算法一起使用流迭代器

由于算法是基于迭代器操作实现的,而流迭代器定义了一些迭代器操作。由于流迭代器操作,因此,至少可在一些泛型算法上使用这类迭代器。

    //从文件中读取一些数,再将读取的不重复的数写到标准输出
    ifstream inFile("input");
    istream_iterator
  
    in_iter(inFile),eof;

    vector
   
     iVec(in_iter,eof); sort(iVec.begin(),iVec.end()); ostream_iterator
    
      out_iter(cout," "); unique_copy(iVec.begin(),iVec.end(),out_iter); 
    
   
  

    //第二种方式输出
    vector
  
   ::iterator end_unique = unique(iVec.begin(),iVec.end());
    cout << endl;
    for (vector
   
    ::iterator iter = iVec.begin(); iter != end_unique; ++iter) { *out_iter ++ = *iter; } 
   
  

//P353 习题11.16
int main()
{
    ifstream inFile("input");

    istream_iterator
  
    in_iter(inFile),eof;
    ostream_iterator
   
     out_iter(cout," "); while (in_iter != eof) { *out_iter ++ = *in_iter ++; } } 
   
  

//习题11.17
int main()
{
    ifstream inFile("input");

    istream_iterator
  
    in_iter(inFile),eof;
    vector
   
     iVec(in_iter,eof); for (vector
    
     ::iterator iter = iVec.begin(); iter != iVec.end(); ++iter) { cout << *iter << endl; } } 
    
   
  

//习题11.18 本题集合了iostream迭代器,文件流
int main()
{
    istream_iterator
  
    in_iter(cin),eof;
    ofstream outFile1("output1"),outFile2("output2");

    ostream_iterator
   
     out_iter1(outFile1," "),out_iter2(outFile2,"\n"); while (in_iter != eof) { if (*in_iter % 2) { *out_iter1 ++ = *in_iter ++; } else { *out_iter2 ++ = *in_iter ++; } } } 
   
  

三、反向迭代器

反向迭代器是一种反向遍历容器的迭代器:从最后一个元素到第一个元素遍历容器。反向迭代器将自增/自减的含义反过来了:对于反向迭代器,++运算将访问前一个元素,而—元素将访问下一个元素。

容器定义的rbegin和rend成员,分别返回指向容器尾元素和首元素前一位置的反向迭代器。

\
    //逆序输出vector对象中的元素
    vector
  
    iVec;
    for (vector
   
    ::size_type i = 0; i != 10; ++i) { iVec.push_back(i); } for (vector
    
     ::reverse_iterator r_iter = iVec.rbegin(); r_iter != iVec.rend(); ++r_iter) { cout << *r_iter << endl; } 
    
   
  

虽然颠倒自增和自减这两个操作符的意义似乎容易使人迷惑,但是它让程序员可以透明地向前或向后处理容器。例如,为了以降序排列vector,只需向sort传递一对反向迭代器:

    sort(iVec.rbegin(),iVec.rend());

当然,如果不嫌麻烦,也可以这样:

    sort(iVec.begin(),iVec.end(),cmp);

cmp函数定义如下:

bool cmp(int a,int b)
{
    return a > b;
}

1、反向迭代器需要使用自减操作符

从一个既支持--也支持++的迭代器就可以定义反向迭代器。毕竟,反向迭代器的目的是移动迭代器反向遍历序列。标准容器上的迭代器既支持自增运算,也支持自减运算。但是,流迭代器却不然,由于不能反向遍历流,因此流迭代器不能创建反向迭代器

2、反向迭代器与其他迭代器之间的关系

输出 string对象line中的第一个单词。使用find可很简单地实现这个任务:

    string::iterator comma = find(line.begin(),line.end(),',');
    cout << string(line.begin(),comma) << endl;

如果要输出列表中的最后一个单词,可以使用反向迭代器:

    string::reverse_iterator rcomma = find(line.rbegin(),line.rend(),',');
    //下面的输出结果可能不能满足你的要求...
    cout << string(line.rbegin(),rcomma) << endl;

如果line中的最后一个单词是Primer,那么,输出的结果为:remirP【是不是很不可思议?】见下图:

\

使用反向迭代器时,以逆序从后向前处理string对象。为了得到正确的输出,必须将反向迭代器line.rbegin()和 rcomma转换为从前向后移动的普通迭代器。其实没必要转换lin