C++ 学习笔记之(10) - 泛型算法和迭代器
标准库容器定义的操作结合非常小,为了实现更丰富的功能,标准库定义了一组反省算法。
概述
大多数算法定义在头文件algorithm
中,头文件numeric
中定义了一组数值泛型算法
- 迭代器令算法不依赖于容器,但依赖于元素类型的操作,比如元素类型的
==
运算符 - 泛型算法本身不会执行容器的操作,他们只会运行于迭代器之上,故算法永远不会改变底层容器的大小
初识泛型算法
除了少数列外,标准库算法都对一个范围内的元素进行操作。此元素范围被称为输入范围
。接受输入范围的算法总是使用前两个参数表示此范围,两个参数分别是指向要处理的第一个元素和尾元素之后位置的迭代器。
只读算法
某些算法只读取输入范围内的元素,而从不改变元素
accumulate
:定义在头文件numeric
中,求和算法, 第三个参数的类型决定了函数使用那个加法运算符以及返回值的类型。// 对 vec 中的元素求和,初识为 0 int sum = accumulate(vec.cbegin(), vec.cend(), 0); // 链接 v 中所有 string 元素 string num = accumulate(v.cbegin(), v.cend(), string(""));
equal
:确定两个序列是否保存相同的值// roster2 中的元素数目应该至少与 roster1 一样多 equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());
那些只接受一个单一迭代器来表示第二个序列的算法,都假定第二个序列至少与第一个序列一样长
写容器元素的算法
某些算法将新值赋予序列中的元素
算法并不会执行容器操作,故不可能改变容器大小
一些算法从两个序列中读取元素,构成这两个序列的元素可以来自于不同的容器类型
若第二个序列是第一个序列的子集,则程序会产生严重错误
插入迭代器(insert iterator):一种向容器中添加元素的迭代器
拷贝算法:另一个向目的位置迭代器指向的输出序列中的元素写入数据的算法
// 把 a1 的内容拷贝到 a2, ret 指向拷贝到 a2 的尾元素之后的位置 auto ret = copy(begin(a1), end(a1), a2); // 将所有值为 0 的元素改为 42 replace(ilst.begin(), ilst.end(), 0, 42);
重排容器元素的算法
某些算法会重排容器中元素的顺序, 比如sort
- 举例:消除文本中重复单词
- 首先将
vector
排序,使用sort
- 然后使用
unique
算法重排vector
,使得不重复的单词出现在vector
前面,返回指向不重复值范围末尾的迭代器 - 使用容器操作真正删除元素
- 首先将
- 标准库算法对迭代器而不是容器操作,故算法不能(直接)添加或删除元素
定制操作
很多算法会比较输入序列中的元素,默认使用元素类型的<
或==
运算符,也可以使用自定义操作代替
向算法传递函数
谓词:可调用的表达式,返回结果是一个能用作条件的值,接受谓词参数的算法对输入序列中的元素调用谓词
- 一元谓词:接受单一参数
- 二元谓词:接受两个参数
// 比较函数,用来按长度排序单词 bool isShorter(const string &s1, const string &s2) { return s1.size() < s2.size(); } // 按长度由断至长排序 words sort(words.begin(), words.end(), isShorter);