C++ STL 算法详解
一、非变动型算法
这类算法在处理数据时不更改原始容器内容。
1.1 元素搜索算法
find(start, finish, target):定位首个匹配目标值的元素,返回其迭代器;若不存在则返回finish。find_if(start, finish, condition):找出首个符合特定条件的元素。find_end(start, finish, sub_start, sub_finish):寻找子序列最后出现的位置。
vector<int> data = {1, 3, 5, 7, 9};
// 定位数值为5的项
auto pos = find(data.begin(), data.end(), 5);
if (pos != data.end()) {
cout << "found: " << *pos << endl; // 输出:5
}
// 寻找首个大于6的项目
auto pos2 = find_if(data.begin(), data.end(), [](int val) {
return val > 6;
});
cout << "first >6: " << *pos2 << endl; // 输出:7
// 子串查询示例
vector<int> pattern = {3, 5};
auto pos3 = find_end(data.begin(), data.end(), pattern.begin(), pattern.end());
if (pos3 != data.end()) {
cout << "subsequence starts at index: " << pos3 - data.begin() << endl; // 输出:1
}
1.2 统计类算法
count(start, finish, target):统计等于target的元素数量。count_if(start, finish, condition):统计满足condition的元素数目。
std::vector<int> items = {1, 2, 3, 2, 4, 2};
int total = std::count(items.begin(), items.end(), 2); // 结果为3
int even_total = std::count_if(items.begin(), items.end(), [](int val) {
return val % 2 == 0;
}); // 结果为4
1.3 遍历执行算法
对指定区间内每一项应用函数对象:
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), [](int& item) {
item *= 2; // 每个元素翻倍
});
// 此时numbers变为{2, 4, 6, 8, 10}
1.4 相等性判断算法
equal(range1_start, range1_end, range2_start):判定两个范围是否一致。mismatch(range1_start, range1_end, range2_start):获取首组不同元素对应的迭代器对。
vector<int> first = {1, 2, 3};
vector<int> second = {1, 2, 4};
vector<int> third = {1, 2, 3, 4};
// 对比first和second前三项
bool match = equal(first.begin(), first.end(), second.begin());
cout << "first == second? " << boolalpha << match << endl; // 输出:false
// 查找first与third首个差异点
auto diff_pair = mismatch(first.begin(), first.end(), third.begin());
if (diff_pair.first != first.end()) {
cout << "difference: " << *diff_pair.first << " vs " << *diff_pair.second << endl; // 无输出(相同)
}
1.5 条件验证算法
all_of(start, finish, condition):确认所有元素都满足条件。any_of(start, finish, condition):检测是否有任意元素满足条件。none_of(start, finish, condition):确保没有任何元素满足条件。
std::vector<int> values = {2, 4, 6, 8};
bool allEven = std::all_of(values.begin(), values.end(), [](int num) {
return num % 2 == 0;
}); // true
bool anyOdd = std::any_of(values.begin(), values.end(), [](int num) {
return num % 2 != 0;
}); // false
bool noNegative = std::none_of(values.begin(), values.end(), [](int num) {
return num < 0;
}); // true
二、变动型算法
此类算法会对容器中的数据进行修改操作。
2.1 数据复制算法
copy(source_start, source_end, destination):将源区间的元素拷贝至目标位置。copy_if(source_start, source_end, destination, condition):仅拷贝符合条件的元素。
vector<int> origin = {1, 2, 3, 4, 5};
vector<int> target(5);
// 全部复制
copy(origin.begin(), origin.end(), target.begin()); // target: [1,2,3,4,5]
// 只复制偶数
vector<int> evens_only;
copy_if(origin.begin(), origin.end(), back_inserter(evens_only), [](int val) {
return val % 2 == 0;
}); // evens_only: [2,4]
2.2 映射变换算法
将输入范围映射到输出范围:
vector<int> inputs = {1, 2, 3};
vector<int> outputs(3);
// 单参数转换
transform(inputs.begin(), inputs.end(), outputs.begin(), [](int x) {
return x * x;
}); // outputs: [1,4,9]
// 双参数转换
vector<int> left = {1, 2, 3};
vector<int> right = {4, 5, 6};
vector<int> sums(3);
transform(left.begin(), left.end(), right.begin(), sums.begin(), [](int a, int b) {
return a + b;
}); // sums: [5,7,9]
2.3 替换算法
replace(start, finish, old_value, new_value):替换所有旧值为新值。replace_if(start, finish, condition, new_value):根据条件替换。replace_copy(start, finish, destination, old_value, new_value):复制过程中替换(不影响原数组)。
vector<int> dataset = {1, 2, 3, 2, 5};
// 将所有2替换为20
replace(dataset.begin(), dataset.end(), 2, 20); // dataset: [1,20,3,20,5]
// 将大于10的元素设为0
replace_if(dataset.begin(), dataset.end(), [](int x) {
return x > 10;
}, 0); // dataset: [1,0,3,0,5]
// 复制时将3替换为300
vector<int> result;
replace_copy(dataset.begin(), dataset.end(), back_inserter(result), 3, 300); // result: [1,0,300,0,5]
2.4 删除算法
remove(start, finish, value):逻辑上移除指定值,返回新的结束迭代器。remove_if(start, finish, condition):按条件逻辑删除元素。
vector<int> list = {1, 2, 3, 2, 4};
// 移动所有2到尾部
auto newEnd = remove(list.begin(), list.end(), 2); // list: [1,3,4,2,2]
// 实际删除这些元素
list.erase(newEnd, list.end()); // list: [1,3,4]
// 结合lambda表达式清除偶数
list = {1, 2, 3, 4, 5};
list.erase(remove_if(list.begin(), list.end(), [](int x) {
return x % 2 == 0;
}), list.end()); // list: [1,3,5]
2.5 去重算法
消除连续重复项:
std::vector<int> sequence = {1, 1, 2, 2, 3, 3, 3, 4, 5};
auto endIter = std::unique(sequence.begin(), sequence.end());
sequence.erase(endIter, sequence.end()); // sequence变为{1, 2, 3, 4, 5}
2.6 反转算法
颠倒序列顺序:
std::vector<int> order = {1, 2, 3, 4, 5};
std::reverse(order.begin(), order.end()); // order变为{5, 4, 3, 2, 1}
2.7 循环移位算法
调整元素位置使其循环左移:
std::vector<int> elements = {1, 2, 3, 4, 5};
std::rotate(elements.begin(), elements.begin() + 2, elements.end()); // elements变为{3, 4, 5, 1, 2}
2.8 打乱算法
随机化元素排列:
#include <random>
#include <algorithm>
std::vector<int> samples = {1, 2, 3, 4, 5};
std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(samples.begin(), samples.end(), gen); // 随机打乱samples
三、排序相关算法
3.1 排序算法
sort(start, finish):快速排序,默认升序。stable_sort(start, finish):稳定排序,保持相等元素原有次序。partial_sort(start, middle, finish):局部排序,使前半段为最小元素。
std::vector<int> unsorted = {5, 3, 1, 4, 2};
std::sort(unsorted.begin(), unsorted.end()); // 升序,unsorted变为{1, 2, 3, 4, 5}
std::sort(unsorted.begin(), unsorted.end(), std::greater<int>()); // 降序,unsorted变为{5, 4, 3, 2, 1}
std::sort(unsorted.begin(), unsorted.end(), [](int a, int b) {
return a < b;
}); // 自定义比较
std::vector<std::pair<int, int>> pairs = {{1, 2}, {2, 1}, {1, 1}, {2, 2}};
std::stable_sort(pairs.begin(), pairs.end(), [](const auto& lhs, const auto& rhs) {
return lhs.first < rhs.first;
});
std::vector<int> mixed = {5, 3, 1, 4, 2, 6};
std::partial_sort(mixed.begin(), mixed.begin() + 3, mixed.end());
// mixed前三位是1, 2, 3,其余未排序
3.2 分割选择算法
将某个位置的元素置于排序后的正确位置:
std::vector<int> nums = {5, 3, 1, 4, 2, 6};
std::nth_element(nums.begin(), nums.begin() + 2, nums.end());
// nums[2]为3,左侧≤3,右侧≥3
3.3 二分查找算法
要求容器必须已排序:
binary_search(start, finish, target):判断是否存在该值。lower_bound(start, finish, target):返回首个不小于目标值的元素。upper_bound(start, finish, target):返回首个大于目标值的元素。
vector<int> ordered = {1, 3, 3, 5, 7};
// 判断3是否存在
bool found = binary_search(ordered.begin(), ordered.end(), 3); // true
// 查找第一个≥3的元素
auto low = lower_bound(ordered.begin(), ordered.end(), 3);
cout << "lower_bound index: " << low - ordered.begin() << endl; // 输出:1
// 查找第一个>3的元素
auto up = upper_bound(ordered.begin(), ordered.end(), 3);
cout << "upper_bound index: " << up - ordered.begin() << endl; // 输出:3
3.4 归并算法
合并两个有序序列:
vector<int> partA = {1, 3, 5};
vector<int> partB = {2, 4, 6};
vector<int> combined(partA.size() + partB.size());
merge(partA.begin(), partA.end(), partB.begin(), partB.end(), combined.begin()); // combined: [1,2,3,4,5,6]
四、堆结构操作算法
提供堆相关的操作方法:
std::vector<int> heap_data = {4, 1, 3, 2, 5};
std::make_heap(heap_data.begin(), heap_data.end()); // 构造最大堆,heap_data变为{5, 4, 3, 2, 1}
heap_data.push_back(6);
std::push_heap(heap_data.begin(), heap_data.end()); // 插入新元素,heap_data变为{6, 4, 5, 2, 1, 3}
std::pop_heap(heap_data.begin(), heap_data.end()); // 弹出堆顶,heap_data变为{5, 4, 3, 2, 1, 6}
int top = heap_data.back(); // 获取最大元素6
heap_data.pop_back(); // 删除堆顶
std::sort_heap(heap_data.begin(), heap_data.end()); // 堆排序成升序,heap_data变为{1, 2, 3, 4, 5}
五、极值查找算法
5.1 最大最小值提取
int x = 5, y = 3;
int minimum = std::min(x, y); // 3
int maximum = std::max(x, y); // 5
auto minInList = std::min({4, 2, 8, 5, 1}); // 1
auto maxInList = std::max({4, 2, 8, 5, 1}); // 8
5.2 区间最值定位
std::vector<int> array = {3, 1, 4, 2, 5};
auto minPos = std::min_element(array.begin(), array.end()); // 指向1
auto maxPos = std::max_element(array.begin(), array.end()); // 指向5
5.3 同时获取最值
std::vector<int> collection = {3, 1, 4, 2, 5};
auto extremes = std::minmax_element(collection.begin(), collection.end());
// extremes.first指向1,extremes.second指向5
六、数值运算算法
6.1 累积求和
#include <numeric>
std::vector<int> digits = {1, 2, 3, 4, 5};
int sumResult = std::accumulate(digits.begin(), digits.end(), 0); // 和为15
int productResult = std::accumulate(digits.begin(), digits.end(), 1, std::multiplies<int>()); // 乘积为120
6.2 内积计算
std::vector<int> vectorA = {1, 2, 3};
std::vector<int> vectorB = {4, 5, 6};
int dotProduct = std::inner_product(vectorA.begin(), vectorA.end(), vectorB.begin(), 0); // 1*4 + 2*5 + 3*6 = 32
6.3 序列填充
std::vector<int> fillTarget(5);
std::iota(fillTarget.begin(), fillTarget.end(), 10); // 填充为10, 11, 12, 13, 14
6.4 部分累积
std::vector<int> base = {1, 2, 3, 4, 5};
std::vector<int> partialSums(base.size());
std::partial_sum(base.begin(), base.end(), partialSums.begin()); // partialSums变为{1, 3, 6, 10, 15}
6.5 差分计算
std::vector<int> input = {1, 2, 3, 4, 5};
std::vector<int> differences(input.size());
std::adjacent_difference(input.begin(), input.end(), differences.begin()); // differences变为{1, 1, 1, 1, 1}
七、其他实用算法
7.1 动态赋值
std::vector<int> generated(5);
int counter = 0;
std::generate(generated.begin(), generated.end(), [&counter]() {
return counter++;
}); // 填充为0, 1, 2, 3, 4
7.2 指定长度赋值
std::vector<int> limited(5);
int startValue = 10;
std::generate_n(limited.begin(), 3, [&startValue]() {
return startValue++;
}); // 前三项为10, 11, 12,其余不变
7.3 子集包含检验
std::vector<int> fullSet = {1, 2, 3, 4, 5};
std::vector<int> subset = {2, 4};
bool contained = std::includes(fullSet.begin(), fullSet.end(), subset.begin(), subset.end()); // true
7.4 集合操作
std::vector<int> setA = {1, 2, 3, 4, 5};
std::vector<int> setB = {3, 4, 5, 6, 7};
std::vector<int> results;
// 并集
std::set_union(setA.begin(), setA.end(), setB.begin(), setB.end(), std::back_inserter(results));
// results为{1, 2, 3, 4, 5, 6, 7}
// 交集
results.clear();
std::set_intersection(setA.begin(), setA.end(), setB.begin(), setB.end(), std::back_inserter(results));
// results为{3, 4, 5}
// 差集 (setA - setB)
results.clear();
std::set_difference(setA.begin(), setA.end(), setB.begin(), setB.end(), std::back_inserter(results));
// results为{1, 2}
// 对称差集 (setA ∪ setB - setA ∩ setB)
results.clear();
std::set_symmetric_difference(setA.begin(), setA.end(), setB.begin(), setB.end(), std::back_inserter(results));
// results为{1, 2, 6, 7}
八、常见疑问解答
- `sort` 与 `stable_sort` 区别?
sort使用快排优化版(introsort),不稳定,O(n log n)。stable_sort采用归并排序,稳定,O(n log n),内存消耗稍高。
- 为何`remove`需配合`erase`使用?
remove仅将有效元素前移,返回新边界,不实际缩减尺寸。erase负责物理删除多余部分,改变真实大小。
- 哪些算法要求预排序?
- 二分查找系(
binary_search,lower_bound,upper_bound) - 集合操作系(
set_intersection,set_union等) merge等,依赖有序性提升效率(如O(log n))。
- 二分查找系(