这周的课讲了将泛型算法。现在将泛型算法收集下,备用。
(1)泛型算法用迭代器来解决第一个要求:遍历容器。所有迭代器都支持自增操作符,从一个元素定位下一个元素,并提供解引用操作符访问元素的值
(2)算法也许会改变存储在容器中的元素的值,也许会在容器内移动元素,但是,算法从不直接添加或删除元素。
【 只读算法】
(3)只读算法是 accumulate,该算法在 numeric 头文件中定义。 accumulate 带有三个形参。头两个形参指定要累加的元素范围。第三个形参则是累加的初值。 假设 vec 是一个 int 型的 vector 对象,下面的代码:
// sum the elements in vec starting the summation with the value 42
int sum = accumulate(vec.begin(), vec.end(), 42);
将 sum 设置为 vec 的元素之和再加上 42。 首先,调用该函数时必须传递一个起始值,否则,accumulate 将不知道使用什么起始值。 其次,容器内的Section 11.2. A First Look at the Algorithms元素类型必须与第三个实参的类型匹配,或者可转换为第三个实参的类型。
(4) find_first_of 函数。 这个算法带有两对迭代器参数来标记两段元素范围,在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素。如果找不到元素,则返回第一个范围的 end 迭代器。
size_t cnt = 0;
list::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;
注意:find_first_of,带有两对迭代器参数。每对迭代器中,两个实参的类型必须精确匹配,但不要求两对之间的类型匹配。特别是,元素可存储在不同类型序列中,只要这两序列的元素可以比较即可。
【 写容器元素的算法】**********************************************************
(5) fill 函数,写入到输入序列的算法 fill 带有一对迭代器形参,用于指定要写入的范围,而所写的值是它的第三个形参的副本。执行时,将该范围内的每个元素都设为给定的值。如果输入范围有效,则可安全写 入。这个算法只会对输入范围内已存在的元素进行写入操作。
fill(vec.begin(), vec.end(), 0); // reset each element to 0
// set subsequence of the range to 10
fill(vec.begin(), vec.begin() + vec.size()/2, 10);
(6) fill_n函数,不检查写入操作的算法 fill_n 函数带有的参数包括:一个迭代器、一个计数器以及一个值。该函数从迭代器指向的元素开始,将指定数量的元素设置为给定的值。fill_n 函数假定对指定数量的元 素做写操作是安全的。 注意:初学者常犯的错误的是:在没有元素的空容器上调用 fill_n 函数(或者类似的写元素算法):
*****************************************************
vectorvec; // empty vector
// disaster: attempts to write to 10 (nonexistent) elements in vec
fill_n(vec.begin(), 10, 0);
//vec 是空的,其结果未定义,很可能导致严重的运行时错误。 *****************************************************
(7) copy 函数,写入到目标迭代器的算法 copy 带有三个迭代器参数:头两个指定输入范围,第三个则指向目标序列的一个元素。传递给 copy 的目标序列必须至少要与输入范围一样大。 假设 ilst 是一个存放 int 型数据的 list 对象,可如下将它 copy 给一个 vector 对象:
vectorivec; // empty vector
// copy elements from ilst into ivec
copy (ilst.begin(), ilst.end(), back_inserter(ivec));
(8)算法的 _copy 版本 有些算法提供所谓的“复制(copying)”版本。这些算法对输入序列的元素做出处理,但不修改原来的元素,而是创建一个新序列存储元素的处理结果。但不修改原来的元素, 而是创建一个新序列存储元素的处理结果。
(9)replace 算法,对输入序列做读写操作,将序列中特定的值替换为新的值 该算法带有四个形参:一对指定输入范围的迭代器和两个值。每一个等于 第一值的元素替换成第二个值。
// replace any element with value of 0 by 42
replace(ilst.begin(), ilst.end(), 0, 42);
(10)replace_copy 这个算法接受第三个迭代器实参,指定保存调整后序列的目标位置。
// create empty vector to hold the replacement vector<i>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)sort 算法 sort 算法带有两个迭代器实参,指出要排序的元素范围。这个算法使用小于(<)操作符比较元素。
(12)unique 算法,该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器,表示无重复的值范围的结束。 它带有两个指定元素范围的迭代器参数。 注:调用 unique“删除”了相邻的重复值。给“删除”加上引号是因为 unique 实际上并没有删除任何元素,而是将无重复的元素复制到序列的前端,从而覆盖相邻的重复元素。unique 返回的迭代器指向超出无重复的元素范围末端的下一位置。(想真正删除元素要与erase函数连用)
(13)stable_sort 算法,有着相同长度的元素还能以字典次序的不同而区分 stable_sort 算法有第三个形参:比较元素所使用的谓词函数的名字。这个谓词函数必须接受两个实参,实参的类型必须与元素类型相同,并返回一个可用作条件检测的值。
// sort words by size, but maintain alphabetic order for words of the same size stable_sort(words.begin(), words.end(), isShorter);
// comparison function to be used to sort by word length
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
(14)count_if 算法,统计个数 执行 count_if 时,首先读取它的头两个实参所标记的范围内的元素。每读出一个元素,就将它传递给第三个实参表示的谓词函数。此谓词函数。此谓词函数需要单个元素类型 的实参,并返回一个可用作条件检测的值。count_if 算法返回使谓词函数返回条件成立的元素个数。 vector::size_type wc =count_if(words.begin(), words.end(), GT6);
// determine whether a length of a given word is 6 or more
bool GT6(const string &s)
{
return s.size() >= 6;
}
【 再谈迭代器】****************************************************************
(15)插入迭代器(insert iterators):这类迭代器与容器绑定在一起,实现在容器中插入元素的功能。 插入器是一种迭代器适配器,带有一个容器参数,并生成一个迭代器,用于在指定容器中插入元素。通过插入迭代器赋值时,迭代器将会插入一个新的元素。C++ 语言提供了三种插入器,其差别在于插入元素的位置不同:
(a)back_inserter,创建使用 push_back 实现插入的迭代器。
(b)front_inserter,使用 push_front 实现插入。
(c)inserter,使用 insert 实现插入操作。除了所关联的容器外,inserter 还带有第二实参:
指向插入起始位置的迭代器。
注:front_inserter 需要使用 push_front,只有当容器提供 push_front 操作时,才能使用 front_inserter。在 vector 或其他没有 push_front 运算的容器上使用front_inserter,将产生错下载文档到电脑,查找使用更方便1下载券 131人已下载下载还剩2页未读,继续阅读误。
listilst, ilst2, ilst3;
// empty lists
// after this loop ilst contains: 3 2 1 0
for (list::size_type i = 0; i != 4; ++i)
ilst.push_front(i);
// after copy ilst2 contains: 0 1 2 3
copy (ilst.begin(), ilst.end(), front_inserter(ilst2));
// after copy, ilst3 contains: 3 2 1 0
copy (ilst.begin(), ilst.end(),
inserter (ilst3, ilst3.begin()));
在复制并创建 ilst2 的过程中,元素总是在这个 list 对象的所有元素之前插入。而在复制创建 ilst3 的过程中,元素则在 ilst3 中的固定位置插入。刚开始时,这个插入 位置是此 list 对象的头部,但插入一个元素后,就不再是首元素了。
(16) iostream 迭代器
【注】流迭代器都是类模板:任何已定义输入操作符(>> 操作符)的类型都可以定义 istream_iterator。类似地,任何已定义输出操作符(<< 操作符)的类型也可定义ostream_iterator。
istream_iteratorcin_it(cin); // reads ints1 from cin
istream_iteratorend_of_stream; // end iterator value
// writes Sales_items from the ofstream named outfile
// each element is followed by a space ofstream outfile;
在创建 istream_iterator 时,可直接将它绑定到一个流上。另一种方法是在创建时不提供实参,则该迭代器指向超出末端位置。ostream_iterator 不提供超出末端迭代器。 在创建 ostream_iterator 对象时,可提供第二个(可选的)实参,指定将元素写入输出流时使用的分隔符。分隔符必须是 C 风格字符串。因为它是 C 风格字符串,所以必须以空字符结束;否则,其行为将是未定义的。
【注】流迭代器的限制:
(a)不可能从 ostream_iterator 对象读入,也不可能写到 istream_iterator 对象中。
(b)一旦给 ostream_iterator 对象赋了一个值,写入就提交了。赋值后,没有办法再改变这个值。此外,ostream_iterator 对象中每个不同的值都只能正好输出一次。
(c)ostream_iterator 没有 -> 操作符。
istream_iteratorcin_it(cin); // reads ints from cin
istream_iteratorend_of_stream; // end iterator value
// initialize vec from the standard input:
vectorvec(cin_it, end_of_stream);
sort(vec.begin(), vec.end());
// writes ints to cout using " " as the delimiter
ostream_iterator<int>output(cout, " ");
// write only the unique elements in vec to the standard output
unique_copy(vec.begin(), vec.end(), output);
输入是: 23 109 45 89 6 34 12 90 34 23 56 23 8 89 23 输出是: 6 8 12 23 34 45 56 89 90 109