算法
C++ 算法库是函数集合,旨在更轻松地编写正确、高效、富有表现力和可重用的代码。
它提供了一组通用、高度优化的算法,可用于执行各种任务,例如在列表中搜索项目、对数据集合进行排序或操作容器的内容。
使用算法库的主要好处之一是它允许您编写更易于理解且不易出错的代码。所有算法都具有几乎普遍认可的名称,这有助于理解使用它们的某些代码部分的作用,而无需进行大量深入研究。由于标准库中的算法经过了彻底的测试和优化,您可以依靠它们正确高效地工作。这可以节省您开发软件的时间和精力,并有助于降低在代码中引入错误的风险。
算法库的另一个好处是它促进了代码重用。通过使用库提供的算法,您可以避免重新实现常见的操作,这可以节省时间并使代码更易于维护。
总的来说,C++ 算法库是 C++ 程序员的重要工具,它使编写可靠、高效和可重用的代码变得更容易。
用法
要使用这些算法,您必须包含 <algorithm>
头文件,如下所示:
#include <algorithm>
然后您可以在代码中使用它们
- 区间版本
- 普通版本
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = { 5, 12, 2137, 1, -5, 22, 96 };
std::ranges::sort(numbers);
for(int number : numbers) {
std::cout << number << ' ';
}
}
-5 1 5 12 22 96 2137
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = { 5, 12, 2137, 1, -5, 22, 96 };
std::sort(numbers.begin(), numbers.end());
for(int number : numbers) {
std::cout << number << ' ';
}
}
-5 1 5 12 22 96 2137
区间版本 vs 普通版本
如您在上面的示例中看到的,算法有两种版本:区间版本和普通版本。区间版本随 C++20 标准引入 C++。如果您有足够新的编译器,您应该能够使用它。
两者之间的基本区别在于,普通版本只接受迭代器,而区间版本更方便,允许传递整个区间并启用使用投影。
区间版本也不易出错,因为您不会不小心传递无效的迭代器(它也比普通版本更好地处理一些高级问题)。
综上所述,使用区间版本更加有益和方便,因此如果可以,请优先选择区间版本。
区间和迭代器
迭代器
迭代是重复一个过程的动作,在容器的情况下,迭代意味着以特定顺序遍历容器,同时获取其每个元素。
迭代器是具有指针语义的特殊对象(具有某些语义基本意味着行为像某些东西,指针语义意味着迭代器对象在大多数方面都像指针一样,它们可以被解引用,递增等。指针也是有效的迭代器),它们用于迭代容器(如字符串、数组、映射、集合等)。
它们通过 begin()
和 end()
函数及其变体获得
cbegin()
/cend()
- 返回容器的常量迭代器(您无法通过它更改内容)rbegin()
/rend()
- 返回容器的反向迭代器(按相反顺序迭代)crbegin()
/crend()
- 返回容器的常量反向迭代器(按相反顺序迭代,并且您无法通过它更改内容)
并非所有容器都具有所有变体,例如 std::unordered_set 没有 r
和 cr
版本。
不同的迭代器有不同的类型,它们的工作方式略有不同,但是您可以使用迭代器做的最基本的事情是
- 递增它(
it++
和++it
),它遍历容器中的下一个对象 - 解引用它(
*it
),它返回迭代器指向的值
以下是使用迭代器与 std::vector 的几个示例
- 打印向量
- 反向打印向量
- 清零向量
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = { 5, 12, 2137, 1, -5, 22, 96 };
// We obtain the iterator here,
// we use the `c` version because we don't intend to change the contents of the vector,
// we only want to print it
std::vector<int>::const_iterator begin = numbers.cbegin();
std::vector<int>::const_iterator end = numbers.cend();
// here we first check if begin is not equal to end, if it is, then we've traversed the entire container
// if it's not, we print the number
// then we increment the iterator
for(; begin != end; ++begin) {
// *begin means "access the element the iterator points to"
std::cout << *begin << ' ';
}
}
5 12 2137 1 -5 22 96
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = { 5, 12, 2137, 1, -5, 22, 96 };
// We obtain the reverse iterator here,
// we use the `c` version because we don't intend to change the contents of the vector,
// we only want to print it
std::vector<int>::const_reverse_iterator begin = numbers.crbegin();
std::vector<int>::const_reverse_iterator end = numbers.crend();
// here we first check if begin is not equal to end, if it is, then we've traversed the entire container
// if it's not, we print the number
// then we increment the iterator
for(; begin != end; ++begin) {
// *begin means "access the element the iterator points to"
std::cout << *begin << ' ';
}
}
96 22 -5 1 2137 12 5
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = { 5, 12, 2137, 1, -5, 22, 96 };
// We obtain the iterator here,
// we use the ordinary version because we do intend to change the contents of the vector,
std::vector<int>::iterator begin = numbers.begin();
std::vector<int>::iterator end = numbers.end();
// here we first check if begin is not equal to end, if it is, then we've traversed the entire container
// if it's not, we print the number
// then we increment the iterator
for(; begin != end; ++begin) {
// *begin means "access the element the iterator points to"
*begin = 0;
}
// Let's print out the container and see the result:
// NOTE: we have to reassign the value to begin because we've changed it while iterating over it
begin = numbers.begin();
for(; begin != end; ++begin) {
// *begin means "access the element the iterator points to"
*begin = 0;
}
}
0 0 0 0 0 0 0
现在,请注意我们每次都必须手动指定类型(std::vector<int>::iterator
,std::vector<int>::reverse_iterator
等)。这不是很方便。为此,您可以使用 auto
占位符
auto begin = numbers.begin();
auto begin = numbers.rbegin();
auto begin = numbers.crbegin();
auto
为我们推断类型,并且没有性能损失。代码以这种方式更易于阅读,因此如果可以,请优先使用它。在此处阅读更多相关信息:auto。
范围
那么范围到底是什么?C++ 中的确切定义和内部工作原理有点复杂,但范围可以定义为我们可以迭代的任何事物。一个数组、向量、字符串、映射等。
所有范围化算法都接受一个范围。正如迭代器可以有不同的类型和略微不同的行为一样,某些范围也与其他范围不同,不能与某些算法一起使用。
算法列表
搜索
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 范围化
- 范围化
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::find (自 C++20 起) | 查找满足特定条件的第一个元素。 |
公开 | find | 查找满足特定条件的第一个元素。 |
公开 | ranges::find_if (自 C++20 起) | 查找满足特定谓词的第一个元素。 |
公开 | find_if | 查找满足特定谓词的第一个元素。 |
公开 | ranges::find_if_not (自 C++20 起) | 查找不满足特定谓词的第一个元素。 |
公开 | find_if_not (自 C++11 起) | 查找不满足特定谓词的第一个元素。 |
公开 | ranges::find_first_of (自 C++20 起) | 在一个范围中搜索另一个范围中的任何元素。 |
公开 | find_first_of | 在一个范围中搜索另一个范围中的任何元素。 |
公开 | ranges::find_end (自 C++20 起) | 在某个范围内查找元素的最后一个序列。 |
公开 | find_end | 在某个范围内查找元素的最后一个序列。 |
公开 | ranges::find_last (自 C++20 起) | 查找等于某个值的最后一个元素。 |
公开 | ranges::find_last_if (自 C++20 起) | 查找满足特定条件的最后一个元素。 |
公开 | ranges::find_last_if_not (自 C++20 起) | 查找不满足特定条件的最后一个元素。 |
公开 | ranges::adjacent_find (自 C++20 起) | 查找满足条件的相邻的两个项目。 |
公开 | adjacent_find | 查找满足条件的相邻的两个项目。 |
公开 | ranges::search (自 C++20 起) | 搜索元素范围。 |
公开 | 搜索 | 搜索元素范围。 |
公开 | ranges::search_n (自 C++20 起) | 在范围中搜索连续的元素序列。 |
公开 | search_n | 在范围中搜索连续的元素序列。 |
确定条件
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 范围化
公开 | ranges::all_of (自 C++20 起) | 检查范围中的所有元素是否满足条件。 |
公开 | all_of (自 C++11 起) | 检查范围中的所有元素是否满足条件。 |
公开 | ranges::any_of (自 C++20 起) | 检查范围中的任何元素是否满足条件。 |
公开 | any_of (自 C++11 起) | 检查范围中的任何元素是否满足条件。 |
公开 | ranges::none_of (自 C++20 起) | 检查范围中是否没有元素满足条件。 |
公开 | none_of (自 C++11 起) | 检查范围中是否没有元素满足条件。 |
公开 | ranges::count (自 C++20 起) | 返回某些元素的数量。 |
公开 | count | 返回某些元素的数量。 |
公开 | ranges::count_if (自 C++20 起) | 返回满足特定条件的元素数量。 |
公开 | count_if | 返回满足特定条件的元素数量。 |
公开 | ranges::mismatch (自 C++20 起) | 查找两个范围首次出现不同的位置。 |
公开 | mismatch | 查找两个范围首次出现不同的位置。 |
公开 | ranges::starts_with (自 C++20 起) | 检查一个范围是否以另一个范围开头。 |
公开 | ranges::ends_with (自 C++20 起) | 检查一个范围是否以另一个范围结尾。 |
其他非修改操作
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::for_each (自 C++20 起) | 将函数应用于元素范围。 |
公开 | for_each | 将函数应用于元素范围。 |
公开 | ranges::for_each_n (自 C++20 起) | 将函数应用于由迭代器和大小组成的元素范围。 |
公开 | for_each_n (自 C++17 起) | 将函数应用于由迭代器和大小组成的元素范围。 |
随机操作
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | random_shuffle (在 C++17 中已移除) | 在 C++14 中已弃用,在 C++17 中已移除,请改用std::shuffle 。 随机重新排列范围内的元素。 |
公开 | ranges::shuffle (自 C++20 起) | 随机重新排列范围内的元素。 |
公开 | shuffle (自 C++11 起) | 随机重新排列范围内的元素。 比 std::random_shuffle 更推荐的方法。 |
公开 | ranges::sample (自 C++20 起) | 从序列中选择 n 个随机元素。 |
公开 | sample (自 C++17 起) | 从序列中选择 n 个随机元素。 |
修改
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
分区
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::is_partitioned (自 C++20 起) | 判断范围是否被给定谓词分区。 |
公开 | is_partitioned (自 C++11 起) | 判断范围是否被给定谓词分区。 |
公开 | ranges::partition (自 C++20 起) | 根据谓词将元素范围分为两组。 |
公开 | partition (自 C++11 起) | 根据谓词将元素范围分为两组。 |
公开 | ranges::partition_copy (自 C++20 起) | 复制范围并将元素分为两组。 |
公开 | partition_copy (自 C++11 起) | 复制范围并将元素分为两组。 |
公开 | ranges::stable_partition (自 C++20 起) | 将元素分为两组,同时保持其相对顺序。 |
公开 | stable_partition | 将元素分为两组,同时保持其相对顺序。 |
公开 | ranges::partition_point (自 C++20 起) | 定位范围的分区点。 |
公开 | partition_point (自 C++11 起) | 定位范围的分区点。 |
排序
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::sort (自 C++20 起) | 将范围(默认为)升序排序。 |
公开 | sort | 将范围(默认为)升序排序。 |
公开 | ranges::stable_sort (自 C++20 起) | 将范围(默认为)升序排序,同时保持相等元素之间的顺序。 |
公开 | stable_sort | 将范围(默认为)升序排序,同时保持相等元素之间的顺序。 |
公开 | ranges::partial_sort (自 C++20 起) | 排序范围的第一个 N 个元素。 |
公开 | partial_sort | 排序范围的第一个 N 个元素。 |
公开 | ranges::partial_sort_copy (自 C++20 起) | 复制并部分排序元素范围。 |
公开 | partial_sort_copy | 复制并部分排序元素范围。 |
公开 | ranges::stable_sort (自 C++20 起) | 部分排序给定范围,确保它由给定元素分区。 |
公开 | stable_sort | 部分排序给定范围,确保它由给定元素分区。 |
公开 | ranges::is_sorted (自 C++20 起) | 检查范围是否已排序。 |
公开 | is_sorted | 检查范围是否已排序。 |
公开 | ranges::is_sorted_until (自 C++20 起) | 查找最大已排序子范围。 |
公开 | is_sorted_until | 查找最大已排序子范围。 |
二分查找(在已排序范围内)
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::binary_search (自 C++20 起) | 在部分有序范围内搜索元素。 |
公开 | binary_search | 在部分有序范围内搜索元素。 |
公开 | ranges::lower_bound (自 C++20 起) | 返回指向第一个不小于给定值的元素的迭代器。 |
公开 | lower_bound | 返回指向第一个不小于给定值的元素的迭代器。 |
公开 | ranges::upper_bound (自 C++20 起) | 返回指向第一个大于给定值的元素的迭代器。 |
公开 | upper_bound | 返回指向第一个大于给定值的元素的迭代器。 |
公开 | ranges::equal_range (自 C++20 起) | 返回与特定键匹配的元素范围。 |
公开 | equal_range | 返回与特定键匹配的元素范围。 |
集合(在已排序范围内)
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::includes (自 C++20 起) | 如果一个序列是另一个序列的子序列,则返回 true 。 |
公开 | includes | 如果一个序列是另一个序列的子序列,则返回 true 。 |
公开 | ranges::set_difference (自 C++20 起) | 计算两个集合之间的差集。 |
公开 | set_difference | 计算两个集合之间的差集。 |
公开 | ranges::set_intersection (自 C++20 起) | 计算两个集合之间的交集。 |
公开 | set_intersection | 计算两个集合之间的交集。 |
公开 | ranges::set_symmetric_difference (自 C++20 起) | 计算两个集合之间的对称差集。 |
公开 | set_symmetric_difference | 计算两个集合之间的对称差集。 |
公开 | ranges::set_union (自 C++20 起) | 计算两个集合之间的并集。 |
公开 | set_union | 计算两个集合之间的并集。 |
已排序范围的其他操作
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::merge (自 C++20 起) | 合并两个已排序的范围。 |
公开 | merge | 合并两个已排序的范围。 |
公开 | ranges::inplace_merge (自 C++20 起) | 就地合并两个已排序的范围。 |
公开 | inplace_merge | 就地合并两个已排序的范围。 |
堆
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::is_heap (自 C++20 起) | 检查给定范围是否为最大堆。 |
公开 | is_heap | 检查给定范围是否为最大堆。 |
公开 | ranges::is_heap_until (自 C++20 起) | 检查给定范围是否为最大堆。 |
公开 | is_heap_until | 检查给定范围是否为最大堆。 |
公开 | ranges::make_heap (自 C++20 起) | 从元素范围创建最大堆。 |
公开 | make_heap | 从元素范围创建最大堆。 |
公开 | ranges::push_heap (自 C++20 起) | 向最大堆添加元素。 |
公开 | push_heap | 向最大堆添加元素。 |
公开 | ranges::pop_heap (自 C++20 起) | 向最大堆添加元素。 |
公开 | pop_heap | 向最大堆添加元素。 |
公开 | ranges::sort_heap (自 C++20 起) | 将最大堆转换为升序排列的元素范围。 |
公开 | sort_heap | 将最大堆转换为升序排列的元素范围。 |
最小值/最大值
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::min (自 C++20 起) | 返回给定值中的最小值。 |
公开 | min | 返回给定值中的最小值。 |
公开 | ranges::max (自 C++20 起) | 返回给定值中的最大值。 |
公开 | max | 返回给定值中的最大值。 |
公开 | ranges::max_element (自 C++20 起) | 返回范围中的最大元素。 |
公开 | max_element | 返回范围中的最大元素。 |
公开 | ranges::min_element (自 C++20 起) | 返回范围中的最小元素。 |
公开 | min_element | 返回范围中的最小元素。 |
公开 | ranges::minmax (自 C++20 起) | 返回给定值中的最小值和最大值。 |
公开 | minmax | 返回给定值中的最小值和最大值。 |
公开 | ranges::minmax_element (自 C++20 起) | 返回范围中的最小和最大元素。 |
公开 | minmax_element | 返回范围中的最小和最大元素。 |
公开 | ranges::clamp (自 C++20 起) | 将值限制在一对边界值之间。 |
公开 | clamp | 将值限制在一对边界值之间。 |
比较
- 范围化
- 普通
- 范围化
- 普通
- 普通
公开 | ranges::equal (自 C++20 起) | 确定两组元素是否相同。 |
公开 | equal | 确定两组元素是否相同。 |
公开 | ranges::lexicographical_compare (自 C++20 起) | 如果一个范围在字典序上小于另一个,则返回 true 。 |
公开 | lexicographical_compare | 如果一个范围在字典序上小于另一个,则返回 true 。 |
公开 | lexicographical_compare_three_way | 使用三向比较比较两个范围。 |
排列
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
公开 | ranges::is_permutation (自 C++20 起) | 确定一个序列是否是另一个序列的排列。 |
公开 | is_permutation (自 C++11 起) | 确定一个序列是否是另一个序列的排列。 |
公开 | ranges::next_permutation (自 C++20 起) | 生成元素范围的下一个字典序更大的排列。 |
公开 | next_permutation (自 C++11 起) | 生成元素范围的下一个字典序更大的排列。 |
公开 | ranges::prev_permutation (自 C++20 起) | 生成元素范围的下一个字典序更小的排列。 |
公开 | prev_permutation (自 C++11 起) | 生成元素范围的下一个字典序更小的排列。 |
数值
- 范围化
- 普通
- 普通
- 普通
- 普通
- 普通
- 普通
- 普通
- 普通
- 普通
- 普通
- 普通
公开 | ranges::iota (自 C++23 起) | 用起始值的连续增量填充一个范围。 |
公开 | iota (自 C++11 起) | 用起始值的连续增量填充一个范围。 |
公开 | accumulate | 对元素范围求和或折叠/规约。 |
公开 | inner_product | 计算两个元素范围的内积。 |
公开 | adjacent_difference | 计算范围中相邻元素之间的差值。 |
公开 | partial_sum | 计算元素范围的部分和。 |
公开 | reduce (自 C++17 起) | 类似于std::accumulate,但顺序不确定。 |
公开 | exclusive_scan (自 C++17 起) | 类似于std::partial_sum,从第 i 个和中排除第 i 个输入元素。 |
公开 | inclusive_scan (自 C++17 起) | 类似于std::partial_sum,从第 i 个和中包含第 i 个输入元素。 |
公开 | transform_reduce (自 C++17 起) | 应用一个可调用对象,然后无序地进行归约。 |
公开 | transform_exclusive_scan (自 C++17 起) | 应用一个可调用对象,然后计算独占扫描。 |
公开 | transform_inclusive_scan (自 C++17 起) | 应用一个可调用对象,然后计算包含扫描。 |
未初始化内存上的操作
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
- 范围化
- 普通
C 算法
- 普通
- 普通
公开 | qsort | 对未指定类型的元素范围进行排序。 |
公开 | bsearch | 在数组中搜索未指定类型的元素。 |