C++标准模板库(STL)中的**算法(Algorithms)**是用于操作容器元素的一组通用函数。它们提供了广泛的功能,包括排序、搜索、修改、计算等。STL的算法设计以迭代器为核心,使得它们能够应用于几乎任何容器类型,从而实现了容器与算法的分离。
1. 算法的分类
STL 中的算法大致可以分为以下几类:
- 非修改算法:不改变容器中的元素。
- 修改算法:会修改容器中的元素。
- 排序算法:对容器中的元素进行排序。
- 排序相关算法:与排序相关但不直接排序的算法。
- 数值算法:专门用于数值计算的算法。
2. 非修改算法
非修改算法不会改变容器中元素的内容。这类算法通常用于搜索、计数、查找最值等操作。
-
for_each
:对范围内的每个元素执行给定的操作。std::vector<int> vec = { 1, 2, 3}; std::for_each(vec.begin(), vec.end(), [](int &n) { n *= 2; });
-
find
:在范围内查找与指定值匹配的第一个元素。auto it = std::find(vec.begin(), vec.end(), 2);
-
count
:计算范围内满足特定条件的元素个数。int count = std::count(vec.begin(), vec.end(), 2);
-
all_of
/any_of
/none_of
:检查范围内的元素是否全部、任意或没有满足特定条件。bool all_positive = std::all_of(vec.begin(), vec.end(), [](int n) { return n > 0; });
-
equal
:判断两个范围内的元素是否相等。bool is_equal = std::equal(vec.begin(), vec.end(), vec2.begin());
3. 修改算法
修改算法会改变容器中元素的内容,如拷贝、移动、替换、移除等操作。
-
copy
:将一个范围内的元素复制到另一个范围中。std::vector<int> vec2(3); std::copy(vec.begin(), vec.end(), vec2.begin());
-
move
:将一个范围内的元素移动到另一个范围中(不复制,而是“移动”资源)。std::vector<int> vec2 = std::move(vec);
-
swap
:交换两个容器的内容。std::swap(vec, vec2);
-
replace
:将范围内满足特定条件的元素替换为新值。std::replace(vec.begin(), vec.end(), 2, 4);
-
remove
:移除范围内满足特定条件的元素,注意该算法并不改变容器的大小。auto it = std::remove(vec.begin(), vec.end(), 2); vec.erase(it, vec.end()); // 实际移除元素
4. 排序算法
STL提供了多种排序算法,用于对容器内的元素进行排序。
-
sort
:对范围内的元素进行升序排序。std::sort(vec.begin(), vec.end());
-
partial_sort
:部分排序,将范围的前n
个元素按顺序排列,其余部分无序。std::partial_sort(vec.begin(), vec.begin() + 3, vec.end());
-
nth_element
:重排范围内的元素,使得第n
个元素处于它在排序后的正确位置。std::nth_element(vec.begin(), vec.begin() + 2, vec.end());
-
stable_sort
:稳定排序算法,排序后相等元素的相对顺序保持不变。std::stable_sort(vec.begin(), vec.end());
5. 排序相关算法
这些算法与排序密切相关,但不直接进行排序。
-
binary_search
:在已排序范围内查找元素,返回是否找到。bool found = std::binary_search(vec.begin(), vec.end(), 3);
-
lower_bound
/upper_bound
:在已排序范围内,查找第一个不小于/大于指定值的位置。auto lb = std::lower_bound(vec.begin(), vec.end(), 3); auto ub = std::upper_bound(vec.begin(), vec.end(), 3);
-
equal_range
:在已排序范围内查找与指定值相等的元素范围。auto range = std::equal_range(vec.begin(), vec.end(), 3);
-
merge
:将两个已排序的范围合并为一个新的已排序范围。std::vector<int> merged(vec.size() + vec2.size()); std::merge(vec.begin(), vec.end(), vec2.begin(), vec2.end(), merged.begin());
6. 数值算法
这些算法用于数值计算,主要包含在 <numeric>
头文件中。
-
accumulate
:计算范围内元素的累积和。int sum = std::accumulate(vec.begin(), vec.end(), 0);
-
inner_product
:计算两个范围内元素的内积。int product = std::inner_product(vec.begin(), vec.end(), vec2.begin(), 0);
-
adjacent_difference
:计算相邻元素的差,并将结果保存到一个新范围。std::vector<int> diff(vec.size()); std::adjacent_difference(vec.begin(), vec.end(), diff.begin());
-
partial_sum
:计算前缀和,并将结果保存到一个新范围。std::vector<int> sum(vec.size()); std::partial_sum(vec.begin(), vec.end(), sum.begin());
7. 其它常见算法
-
max_element
/min_element
:查找范围内的最大值或最小值。auto max_it = std::max_element(vec.begin(), vec.end()); auto min_it = std::min_element(vec.begin(), vec.end());
-
unique
:删除范围内相邻的重复元素。auto it = std::unique(vec.begin(), vec.end()); vec.erase(it, vec.end());
-
reverse
:反转范围内的元素。std::reverse(vec.begin(), vec.end());
-
rotate
:将范围内的元素旋转,使第一个元素成为新范围的第一个元素。std::rotate(vec.begin(), vec.begin() + 1, vec.end());
-
next_permutation
/prev_permutation
:生成范围内元素的下一个/上一个排列。std::next_permutation(vec.begin(), vec.end());
8. STL 算法与迭代器的关系
STL 中的算法大多以迭代器为参数,而非直接操作容器。这种设计使得算法具有极强的泛型性,可以应用于任何支持迭代器的容器。
例如,std::sort
接受两个随机访问迭代器作为参数,这意味着它可以对 std::vector
、std::deque
等容器进行排序,因为这些容器的迭代器支持随机访问。
9. 总结
C++ STL 中的算法提供了强大而灵活的工具集,涵盖了各种常见的操作需求。掌握这些算法的使用技巧不仅可以提高代码的效率,还能增强代码的可读性和维护性。通过理解算法的分类和各自的功能,可以更加有效地利用 STL 来解决复杂的编程问题。
关键点总结:
- 泛型性:STL算法可以与任何支持迭代器的容器配合使用。
- 效率:大多数算法都是高效实现的,如
std::sort
是一种快速排序的实现。 - 灵活性:通过组合不同的算法和迭代器,几乎可以完成所有常见的数据操作需求。