1. 初识泛型算法
1.1 概述
顺序容器只定义了很少的操作,如添加元素、删除元素、访问首尾元素、确定容器是否为空以及获得指向首元素或尾元素之后位置的迭代器等操作。但我们还希望做其他很多有用的操作,比如查找特定元素、替换或删除一个特定值、重排元素顺序等。标准库定义了一组泛型算法来实现这些操作。大多数泛型算法都定义在头文件algorithm中,在头文件numeric中还定义了一组数值泛型算法。下面介绍一个算法示例:
1.find算法
假定我们有一个 vector 容器,数据类型为 int,希望知道该容器中是否包含一个特定值,最简单的方法是使用标准库算法 find。
int val = 42;
auto result = find(vec.begin(), vec.end(), val);
cout << "the value" << val << (result == vec.cend() ? "is not present" : "is present") << endl;
传递给 find 的前两个参数是表示元素范围的迭代器,第三个参数是一个值,即要搜索的值。find 算法将范围内每个元素与要搜索的值进行比较。如果要搜索的值存在,返回指向第一个等于给定值的元素的迭代器。如果范围内搜索不到要找的值,则返回第二个参数来表示搜索失败。
1.2 只读算法
一些算法只会读取其输入范围内的元素而不改变元素。
1.求和算法accumulate
accumulate 定义在头文件numeric中,算法 accumulate 接受三个参数,前两个指出了需要求和的元素的范围,第三个参数是和的初值。
int sum = accumulate(vec.cbegin(), vec.cend(), 0);
注意: 序列中元素的类型必须与第三个参数匹配或者是能够转换为第三个参数的类型,否则无法求和。
2.比较算法equal
equal 用于确定两个序列是否保存相同的值。它将第一个序列中的每个元素与第二个序列中的对应元素进行比较。如果所有对应的元素都相等则返回 true,否则返回 false。此算法接受三个迭代器:前两个表示第一个序列中的元素范围,第三个迭代器表示第二个序列的首元素。
equal(vec1.cbegin(), vec1.cend(), vec2.cbegin()); // vec2中的元素数目至少与vec1的一样多
注意: 可以通过调用 equal 来比较两个不同类型的容器中的元素,只要我们能用相等运算符来比较这两个元素类型即可。
2.3 写容器元素的算法
一些算法会修改容器中元素的值,使用这类算法时必须确保原序列长度不小于算法要写入的元素数目。记住,算法不会执行容器操作,因此使用算法不会改变容器的大小。
1.算法fill
fill 接受一对迭代器表示一个范围,还接受一个值作为第三个参数。fill 用第三个参数来修改迭代器表示的范围中的每个元素。
fill(vec.begin(), vec.end(), 0); // 将每个元素重置为0
2.算法fill_n
fill_n 接受一个迭代器 a,一个计数值 b 和一个值 c,它将值 c 赋予迭代器 a 指向的元素开始的 b 个元素。我们可以用 fill_n 将一个新值赋予vector 中的元素,如下所示:
vector<int>vec(10, 1);
fill_n(vec.begin(), vec.size(), 0); // 将所有元素重置为0
3.back_inserter
一种保证算法有足够元素空间来容纳输出数据的方法是使用插入迭代器,插入迭代器是一种向容器中添加元素的迭代器。通常情况下当我们通过一个迭代器向容器元素赋值时,值被赋予迭代器指向的元素。而当我们通过一个插入迭代器赋值时,一个与赋值号右侧值相等的元素被添加到容器中。back_inserter是定义在头文件iterator中的一个函数,它接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。当我们通过此迭代器赋值时,赋值运算符会调用 push_back 将一个具有给定值的元素添加到容器中,如下所示:
vector<int>vec;
auto it = back_inserter(vec);
*it = 42; // vec添加一个元素42
vector<int> vec2;
fill_n(back_inserter(vec2), 10, 0);
4.算法copy
此算法接受三个迭代器,前两个表示一个输入范围,第三个表示目的序列的起始位置。此算法将输入范围中的元素拷贝到目的序列中,传递给copy的目的序列至少要包含与输入序列一样多的元素。
int a1[] = {
0,1,2,3,4,5,6,7,8,9};
int a2[size(a1)]; // a2和a1一样大
auto ret = copy(begin(a1), end(a1), a2); // 把a1拷贝给a2
copy 返回复制的最后一个元素的下一位置的迭代器。
5.算法replace
replace算法读入一个序列,并将其中所有等于给定值的元素都改为另一个元素。此算法接受四个参数:前两个是迭代器,表示输入序列,第三个是要搜索的元素 a,最后一个是用来替换的元素 b,它将所有等于值 a 的元素替换为值 b。
replace(ist.begin(), ist.end(), 0, 42);
2.4 重排容器元素的算法
1.sort算法
sort 是 C++标准库中的排序算法,用于对给定范围的元素进行排序。sort 的基本语法如下:
#include <algorithm>
std::sort(start_iterator, end_iterator);
// 其中 start_iterator 和 end_iterator 分别是表示排序范围的迭代器
// start_iterator 指向排序范围的起始位置,而 end_iterator 指向排序范围的尾后位置。
sort 的算法示例如下:
int arr[] = {
5, 2, 9, 1, 5, 6};
// 使用 std::begin 和 std::end 获取迭代器
std::sort(std::begin(arr), std::end(arr));
// 输出排序后的数组
for