11.1
关键概念:算法永不执行容器提供的操作
泛型算法本身从不执行容器操作,只是单独依赖迭代器和迭代器操作实现。算法基于迭代器及其操作实现,而并非基于容器操作。这个事实也许比较意外,但本质上暗示了:使用“普通”的迭代器时,算法从不修改基础容器的大小。正如我们所看到的,算法也许会改变存储在容器中的元素的值,也许会在容器内移动元素,但是,算法从不直接添加或删除元素。第 11.3.1 节将介绍标准库提供的另一种特殊的迭代器类:插入器(inserter),除了用于遍历其所绑定的序列之外,还可实现更多的功能。在给这类迭代器赋值时,在基础容器上将执行插入运算。如果算法操纵这类迭代器,迭代器将可能导致在容器中添加元素。但是,算法本身从不这么做。find_first_of的使用
这个算法带有两对迭代器参数来标记两段元素范围,在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素。如果找不到元素,则返回第一个范围的 end 迭代器。假设 roster1 和 roster2 是两个存放名字的 list 对象,可使用 find_first_of 统计有多少个名字同时出现在这两个列表中:
size_t cnt = 0;
list<string>::iterator it = roster1.begin();
// look in roster1 for any name also in roster2
while ((it = find_first_of(it, roster1.end(),roster2.begin(), roster2.end()))!= roster1.end()) {
++cnt;
// we got a match, increment it to look in the rest of roster1
++it;
}
cout << "Found " << cnt<< " names on both rosters" << endl;
11.2.2
算法的 _copy 版本
replace 算法就是一个很好的例子。该算法对输入序列做读写操作,将序列中特定的值替换为新的值。该算法带有四个形参:一对指定输入范围的迭代器和两个值。每一个等于第一值的元素替换成第二个值。
replace(ilst.begin(), ilst.end(), 0, 42);
这个调用将所有值为 0 的实例替换成 42。如果不想改变原来的序列,则调用 replace_copy。这个算法接受第三个迭代器实参,指定保存调整后序列的目标位置。
// create empty vector to hold the replacement
vector<int> ivec;
// use back_inserter to grow destination as needed
replace_copy (ilst.begin(), ilst.end(),back_inserter(ivec), 0, 42);
调用该函数后,ilst 没有改变,ivec 存储 ilst 一份副本,而 ilst 内所有的 0 在 ivec 中都变成了 42。
11.2.3
unique的使用
它带有两个指定元素范围的迭代器参数。该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器,表示无重复的值范围的结束。
stable_sort
sort 和 stable_sort 都是重载函数。其中一个版本使用元素类型提供的小于(<)操作符实现比较。在查找重复元素之前,我们就是用这个 sort 版本对元素排序。第二个重载版本带有第三个形参: 比较元素所使用的谓词函数的名字。这个谓词函数必须接受两个实参,实参的类型必须与元素类型相同,并返回一个可用作条件检测的值。stable_sort 保留相等元素的原始相对位置。
11.3.1
inserter 适配器提供更普通的插入形式。这种适配器带有两个实参:所关联的容器和指示起始插入位置的迭代器。
// position an iterator into ilst
list<int>::iterator it =find (ilst.begin(), ilst.end(), 42);
// insert replaced copies of ivec at that point in ilst
replace_copy (ivec.begin(), ivec.end(),inserter (ilst, it), 100, 0);
首先用 find 定位 ilst 中的某个元素。使用 inserter 作为实参调用replace_copy,inserter 将会在 ilst 中由 find 返回的迭代器所指向的元素前面插入新元素。而调用 replace_copy 的效果是从 ivec 中复制元素,并将其中值为 100 的元素替换为 0 值。ilst 的新元素在 it 所标明的元素前面插入。
在创建 inserter 时,应指明新元素在何处插入。inserter 函数总是在它的迭代器实参所标明的位置前面插入新元素。
11.3.2 iostream 迭代器
istream_iterator<T>in(strm); | 创建从输入流 strm 中读取 T 类型对象的 istream_iterator 对象 |
istream_iterator<T>in; | istream_iterator 对象的超出末端迭代器 |
ostream_iterator<T>in(strm); | 创建将 T 类型的对象写到输出流 strm 的 ostream_iterator 对象 |
ostream_iterator<T> in(strm, delim); | 创建将 T 类型的对象写到输出流 strm 的 ostream_iterator 对象,在写入过程中使用 delim 作为元素的分隔符。delim 是以空字符结束的字符数 组 |
// write one string per line to the standard output
ostream_iterator<string> out_iter(cout, "\n");
// read strings from standard input and the end iterator
istream_iterator<string> in_iter(cin), eof;
// read until eof and write what was read to the standard output
while (in_iter != eof)
// write value of in_iter to standard output
// and then increment the iterator to get the next value from cin
*out_iter++ = *in_iter++;
首先,定义一个 ostream_iterator 对象,用于将 string 类型的数据写到cout 中,每个 string 对象后跟一个换行符。定义两个 istream_iterator 对象,用于从 cin 中读取 string 对象。while 循环类似前一个例子。但是这一次不是将读取的数据存储在 vector 对象中, 而是将读取的数据赋给 out_iter,从而输出到 cout 上。
Exercise 11.18:
编写程序使用 istream_iterator 对象从标准输入读入一系列整数。使用 ostream_iterator 对象将其中的奇数写到一个文件中, 并在每个写入的值后面加一个空格。同样使用 ostream_iterator 对象将偶数写到第二个文件,每个写入的值都存放在单独的行中。#include<iostream>
#include<iterator>
#include<fstream>
using namespace std;
bool GT6(const string &s)
{
return s.size()>=6;
}
int main()
{
ofstream out_file1("text1.txt");
ofstream out_file2("text2.txt");
if(!out_file1||!out_file2)
{
cout<<"can't open file!"<<endl;
return 0;
}
istream_iterator<int> in(cin),end;
ostream_iterator<int> out1(out_file1," ");
ostream_iterator<int> out2(out_file2,"\n");
while(in!=end)
{
if(*in%2!=0)
{
*out1=*in;
out1++;
}
else
{
*out2=*in;
out2++;
}
in++;
}
getchar();
getchar();
return 0;
}
所有反向迭代器类型都提供的成员函数 base ,riter.base( )=iter++
11.3.5
Input iterator(输入迭代器) | 读,不能写;只支持自增运算 |
Output iterator(输出迭代器) | 写,不能读;只支持自增运算 |
Forward iterator(前向迭代器) | 读和写;只支持自增运算 |
Bidirectional iterator(双向迭代器) | 读和写;支持自增和自减运算 |
Random access iterator(随机访问迭代器) | 读和写;支持完整的迭代器算术运算 |
map、set 和 list 类型提供双向迭代器,而 string、vector 和 deque 容器上定义的迭代器都是随机访问迭代器都是随机访问迭代器, 用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator 是输入迭代器,而ostream_iterator 则是输出迭代器。