前言:
C++标准模板库(STL)是每个C++程序员的宝库,它提供了一系列广泛使用的算法,这些算法都包含在 `<algorithm>` 头文件中。STL算法与容器无缝集成,允许开发者编写更加简洁、可读和高效的代码。本文将深入探讨这些算法,并了解如何使用它们来解决实际问题。
算法:
1. 非修改性算法
非修改性算法不会更改容器的内容,主要用于读取或检查容器的内容。例如,`std::for_each` 允许我们对容器中的每个元素应用函数,而 `std::count_if` 可以帮助我们统计满足特定条件的元素数量。这类算法在数据分析和检查中特别有用。
- `std::for_each`: 对范围内的每个元素应用一个函数。
- `std::count`, `std::count_if`: 计算满足某个条件的元素的数量。
- `std::find`, `std::find_if`, `std::find_if_not`: 查找满足某个条件的元素。
- `std::equal`: 检查两个序列是否相等。
1.1 for_each
对范围内的每个元素应用一个函数。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::for_each(v.begin(), v.end(), [](int &n) {
n *= 2;
});
for (const auto &i: v) std::cout << i << ' '; // 输出:2 4 6 8 10
}
1.2 count ,count_if
计算满足某个条件的元素的数量。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
int count = std::count_if(v.begin(), v.end(), [](int n) {
return n % 2 == 0;
});
std::cout << "Number of even elements: " << count; // 输出:Number of even elements: 2
}
1.3 find,find_if,find_if_not
查找满足某个条件的元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
auto it = std::find_if(v.begin(), v.end(), [](int n) {
return n > 3;
});
if (it != v.end()) std::cout << "Found value greater than 3: " << *it; // 输出:Found value greater than 3: 4
}
1.4 equal
检查两个序列是否相等。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {1, 2, 3, 4, 5};
if (std::equal(v1.begin(), v1.end(), v2.begin())) {
std::cout << "The sequences are equal.\n"; // 输出:The sequences are equal.
} else {
std::cout << "The sequences are not equal.\n";
}
}
2. 修改性算法
修改性算法会改变容器的内容。例如,我们可以使用 `std::copy` 将一个容器的内容复制到另一个容器中,或使用 `std::transform` 来对容器中的每个元素应用一个函数并存储结果。这类算法在数据处理和转换中非常实用。
- `std::copy`: 复制一个范围内的元素到另一个位置。
- `std::move`: 移动一个范围内的元素到另一个位置。
- `std::transform`: 对范围内的每个元素应用一个函数,并将结果存储到另一个位置。
- `std::fill`, `std::fill_n`: 用给定值填充一个范围内的元素。
- `std::replace`, `std::replace_if`: 替换满足某个条件的所有元素。
2.1 copy
复制一个范围内的元素到另一个位置。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dest(5);
std::copy(src.begin(), src.end(), dest.begin());
for (const auto &i: dest) std::cout << i << ' '; // 输出:1 2 3 4 5
}
2.2 move
移动一个范围内的元素到另一个位置。
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> src = {"one", "two", "three"};
std::vector<std::string> dest(3);
std::move(src.begin(), src.end(), dest.begin());
for (const auto &str: dest) std::cout << str << ' '; // 输出:one two three
}
2.3 transform
对范围内的每个元素应用一个函数,并将结果存储到另一个位置。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dest(5);
std::transform(src.begin(), src.end(), dest.begin(), [](int n) {
return n * n;
});
for (const auto &i: dest) std::cout << i << ' '; // 输出:1 4 9 16 25
}
2.4 fill,fill_n
用给定值填充一个范围内的元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v(5);
std::fill(v.begin(), v.end(), 10);
for (const auto &i: v) std::cout << i << ' '; // 输出:10 10 10 10 10
}
2.5 replace,replace_if
替换满足某个条件的所有元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::replace_if(v.begin(), v.end(), [](int n) {
return n % 2 == 0;
}, 0);
for (const auto &i: v) std::cout << i << ' '; // 输出:1 0 3 0 5
}
3. 删除性算法
这类算法从容器中删除元素。`std::remove_if` 可以用来删除满足条件的所有元素。使用这些算法可以帮助我们清理数据集。
- `std::remove`, `std::remove_if`: 删除满足某个条件的所有元素。
- `std::unique`: 删除相邻的重复元素。
3.1 remove,remove_if
删除满足某个条件的所有元素。
注意,`std::remove` 和 `std::remove_if` 并不实际删除元素,而是将不满足条件的元素移动到序列的前部,并返回一个迭代器,指向最后一个不需要删除的元素的下一个位置。要完全删除元素,还需要用容器的 `erase` 方法。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
auto new_end = std::remove_if(v.begin(), v.end(), [](int n) {
return n % 2 == 0; // 删除所有偶数
});
v.erase(new_end, v.end());
for (const auto &i: v) std::cout << i << ' '; // 输出:1 3 5
}
3.2 unique
删除相邻的重复元素。
`std::unique` 同样并不实际删除元素,而是重新排列容器中的元素,将重复元素移到容器的尾部,并返回一个迭代器,指向最后一个不重复的元素的下一个位置。为了完全删除重复元素,还需要结合容器的 `erase` 方法。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 1, 2, 3, 3, 3, 4, 4, 5, 5};
auto new_end = std::unique(v.begin(), v.end());
v.erase(new_end, v.end());
for (const auto &i: v) std::cout << i << ' '; // 输出:1 2 3 4 5
}
4. 排序和相关算法
排序和相关算法主要用于对数据集进行排序和查找。例如,`std::sort` 可以对一个范围内的元素进行排序,而 `std::nth_element` 可以找到第n个元素应该在的位置。这类算法在数据排序和查询时特别重要。
- `std::sort`: 对一个范围内的元素进行排序。
- `std::stable_sort`: 对一个范围内的元素进行稳定排序。
- `std::partial_sort`: 对一个范围内的元素进行部分排序。
- `std::nth_element`: 对一个范围内的元素进行部分排序,使得第n个元素位于正确的位置。
4.1 sort
对一个范围内的元素进行排序。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {5, 1, 9, 3, 7};
std::sort(v.begin(), v.end()); // 默认升序排序
for(const auto &i: v) std::cout << i << ' '; // 输出:1 3 5 7 9
}
4.2 stable_sort
对一个范围内的元素进行稳定排序。
`std::stable_sort` 和 `std::sort` 的区别在于,`std::stable_sort` 会保持相等元素的原始相对顺序。
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> v = {"apple", "orange", "banana", "apple"};
std::stable_sort(v.begin(), v.end());
for(const auto &i: v) std::cout << i << ' '; // 相同元素 "apple" 的原始顺序被保持
}
4.3 partial_sort
对一个范围内的元素进行部分排序。
`std::partial_sort` 只确保前n个最小的元素以升序排序,其余元素位置不定。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {5, 1, 9, 3, 7};
std::partial_sort(v.begin(), v.begin() + 3, v.end()); // 前3个元素升序排序
for(const auto &i: v) std::cout << i << ' '; // 输出可能是:1 3 5 9 7
}
4.4 nth_element
对一个范围内的元素进行部分排序,使得第n个元素位于正确的位置。
`std::nth_element` 确保第n个元素位于正确的位置,即它左边的元素都小于它,它右边的元素都大于它。但左右两边的元素不一定是有序的。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {5, 1, 9, 3, 7};
std::nth_element(v.begin(), v.begin() + 2, v.end()); // 保证第3个位置的元素(9)在正确的位置上
for(const auto &i: v) std::cout << i << ' '; // 输出可能是:5 1 3 7 9 或者 1 3 5 7 9 等
}
5. 二分查找算法
二分查找算法在有序序列中进行查找,如 `std::binary_search` 可以在有序序列中查找给定值。这类算法可以快速定位数据,提高检索效率。
- `std::lower_bound`: 查找有序序列中第一个不小于给定值的元素。
- `std::upper_bound`: 查找有序序列中第一个大于给定值的元素。
- `std::binary_search`: 在有序序列中查找给定值。
- `std::equal_range`: 在有序序列中查找等于给定值的元素的范围。
5.1 lower_bound
查找有序序列中第一个不小于给定值的元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 4, 4, 5, 6};
auto it = std::lower_bound(v.begin(), v.end(), 4);
if (it != v.end()) std::cout << "Lower bound of 4: " << *it; // 输出:Lower bound of 4: 4
}
5.2 upper_bound
查找有序序列中第一个大于给定值的元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 4, 4, 5, 6};
auto it = std::upper_bound(v.begin(), v.end(), 4);
if (it != v.end()) std::cout << "Upper bound of 4: " << *it; // 输出:Upper bound of 4: 5
}
5.3 binary_search
在有序序列中查找给定值。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
if (std::binary_search(v.begin(), v.end(), 3)) {
std::cout << "3 is found in the vector"; // 输出:3 is found in the vector
} else {
std::cout << "3 is not found in the vector";
}
}
5.4 equal_range
在有序序列中查找等于给定值的元素的范围。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 4, 4, 5, 6};
auto range = std::equal_range(v.begin(), v.end(), 4);
auto first = range.first;
auto last = range.second;
std::cout << "The equal range of 4: ";
for (auto it = first; it != last; ++it) std::cout << *it << ' '; // 输出:The equal range of 4: 4 4
}
6. 堆算法
堆算法用于操作堆,例如,`std::make_heap` 可以将一个序列转换为一个堆。这类算法在优先队列和调度算法中广泛使用。
- `std::make_heap`: 转换一个序列为堆。
- `std::push_heap`: 向堆中插入一个元素。
- `std::pop_heap`: 从堆中删除最大的元素。
6.1 make_heap
转换一个序列为堆。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2};
std::make_heap(v.begin(), v.end());
std::cout << "Max element (heap top): " << v.front(); // 输出:Max element (heap top): 9
}
6.2 push_heap
向堆中插入一个元素。
向堆中插入元素时,元素应该首先被添加到容器的末尾,然后调用 `std::push_heap`。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {9, 5, 4, 1, 1};
v.push_back(10); // 先将10添加到向量的末尾
std::push_heap(v.begin(), v.end()); // 然后将10添加到堆中
std::cout << "Max element (heap top): " << v.front(); // 输出:Max element (heap top): 10
}
6.3 pop_heap
从堆中删除最大的元素。
要从堆中删除元素,应该首先调用 `std::pop_heap`,这会将最大元素(堆顶元素)与容器的最后一个元素交换,然后从容器中删除最后一个元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {9, 5, 4, 1, 1};
std::pop_heap(v.begin(), v.end()); // 9 和 1 交换位置
int max_element = v.back(); // 获取(原来的)堆顶元素
v.pop_back(); // 从容器中删除(原来的)堆顶元素
std::cout << "Popped element: " << max_element << '\n'; // 输出:Popped element: 9
std::cout << "New max element (heap top): " << v.front(); // 输出:New max element (heap top): 5
}
7. 最大和最小元素算法
这类算法用于查找范围内的最大或最小元素。例如,`std::max_element` 可以找到容器中的最大元素。这些算法在数据分析中非常有用。
- `std::max`, `std::min`: 返回两个元素中的最大值或最小值。
- `std::max_element`, `std::min_element`: 在一个范围内查找最大或最小的元素。
- `std::minmax`, `std::minmax_element`: 在一个范围内同时查找最大和最小的元素。
7.1 max,min
返回两个元素中的最大值或最小值。
#include <algorithm>
#include <iostream>
int main() {
std::cout << "Max: " << std::max(3, 5) << '\n'; // 输出:Max: 5
std::cout << "Min: " << std::min(3, 5) << '\n'; // 输出:Min: 3
}
7.2 max_element,min_element
在一个范围内查找最大或最小的元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2};
auto max_it = std::max_element(v.begin(), v.end());
auto min_it = std::min_element(v.begin(), v.end());
std::cout << "Max Element: " << *max_it << '\n'; // 输出:Max Element: 9
std::cout << "Min Element: " << *min_it << '\n'; // 输出:Min Element: 1
}
7.3 minmax,minmax_element
在一个范围内同时查找最大和最小的元素。
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2};
auto minmax_it = std::minmax_element(v.begin(), v.end());
auto minmax_val = std::minmax({3, 1, 4, 1, 5, 9, 2}); // initializer_list
std::cout << "Max Element: " << *minmax_it.second << " Min Element: " << *minmax_it.first << '\n'; // 输出:Max Element: 9 Min Element: 1
std::cout << "Max Value: " << minmax_val.second << " Min Value: " << minmax_val.first << '\n'; // 输出:Max Value: 9 Min Value: 1
}
8. 数值算法
数值算法主要用于进行数值计算。例如,`std::accumulate` 可以计算一个范围内的元素的和或其他二元操作的累积结果,非常适用于统计学和数据分析。
- `std::iota`: 生成一个递增的序列。
- `std::accumulate`: 计算一个范围内的元素的和或其他二元操作的累积结果。
- `std::inner_product`: 计算两个序列的内积。
- `std::adjacent_difference`: 计算相邻元素的差值。
- `std::partial_sum`: 计算部分和。
8.1 iota
生成一个递增的序列。
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v(5);
std::iota(v.begin(), v.end(), 1); // 生成:1 2 3 4 5
for (const auto& i: v) std::cout << i << ' '; // 输出:1 2 3 4 5
}
8.2 accumulate
计算一个范围内的元素的和或其他二元操作的累积结果。
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
int sum = std::accumulate(v.begin(), v.end(), 0); // 计算和
std::cout << "Sum: " << sum; // 输出:Sum: 15
}
8.3 inner_product
计算两个序列的内积。
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v1 = {1, 2, 3, 4};
std::vector<int> v2 = {5, 6, 7, 8};
int product = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
std::cout << "Inner Product: " << product; // 输出:Inner Product: 70
}
8.4 adjacent_difference
计算相邻元素的差值。`
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 4, 7, 11};
std::vector<int> result(v.size());
std::adjacent_difference(v.begin(), v.end(), result.begin());
for (const auto& i: result) std::cout << i << ' '; // 输出:1 1 2 3 4
}
8.5 partial_sum
计算部分和。
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> result(v.size());
std::partial_sum(v.begin(), v.end(), result.begin());
for (const auto& i: result) std::cout << i << ' '; // 输出:1 3 6 10 15
}
总结:
C++的STL算法提供了一套强大且多样化的工具集,能够帮助开发者有效地处理各种问题。通过结合使用这些算法,我们可以更容易地实现复杂功能,同时保持代码的清晰和高效。在实际开发中,掌握并熟练运用这些算法会极大地提高我们的编程效率和代码质量。