C++: STL 算法
第34课我们学了STL容器,知道了用什么装数据。
但光有容器还不够——你还需要处理数据:查找、排序、统计、变换……
如果自己写,可能要写几十行;用STL算法,一行搞定。
1. STL算法概述
(1) 1.1 什么是STL算法?
STL算法是C++标准库提供的一组通用函数模板,用于操作容器中的数据。
为什么要用STL算法?
| 自己写 | STL算法 |
|---|---|
| 要写循环 | 一行代码 |
| 容易出错 | 经过严格测试 |
| 性能不一定高 | 高度优化 |
| 代码长 | 代码简洁 |
生活类比:
- 自己写算法 = 手洗衣服(费时费力)
- STL算法 = 洗衣机(一键搞定)
(2) 1.2 算法头文件
大多数STL算法在 algorithm 头文件中,数值算法在 numeric 中。
▶ 示例 2:STL算法应用(难度⭐)
#include <algorithm> // 大多数算法
#include <numeric> // 数值算法(accumulate等)
输出:
(程序输出)
(3) 1.3 算法分类
STL算法按功能分为几大类:
| 类别 | 代表算法 | 说明 |
|---|---|---|
| 非修改算法 | find、count、for_each |
不修改容器内容 |
| 修改算法 | copy、transform、replace |
修改容器内容 |
| 排序算法 | sort、stable_sort、partial_sort |
排序相关 |
| 二分查找 | binary_search、lower_bound |
在已排序区间查找 |
| 合并算法 | merge、inplace_merge |
合并有序区间 |
| 数值算法 | accumulate、inner_product |
数值计算 |
| 集合算法 | set_union、set_intersection |
集合运算 |
2. 非修改算法
(1) 2.1 find——查找元素
功能: 在容器中查找指定元素,返回迭代器。
原型:
InputIt find(InputIt first, InputIt last, const T& value);
示例:查找成绩(难度⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88};
// 查找成绩90
auto it = std::find(scores.begin(), scores.end(), 90);
if (it != scores.end()) {
// 计算位置(索引)
int index = std::distance(scores.begin(), it);
std::cout << "找到成绩90,位置:" << index << std::endl;
} else {
std::cout << "没找到成绩90" << std::endl;
}
return 0;
}
运行结果:
找到成绩90,位置:3
💡 提示:
- 找不到时返回
last(通常是end()) - 时间复杂度:O(n)
(2) 2.2 count——计数
功能: 统计容器中等于指定值的元素个数。
示例:统计满分人数(难度⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {100, 85, 100, 92, 78, 100};
// 统计满分(100分)人数
int perfect = std::count(scores.begin(), scores.end(), 100);
std::cout << "满分人数:" << perfect << std::endl; // 输出:3
return 0;
}
(3) 2.3 for_each——遍历
功能: 对容器中每个元素执行指定操作。
示例:打印所有成绩(难度⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88};
// 使用 lambda 表达式打印每个成绩
std::for_each(scores.begin(), scores.end(), (int s) {
std::cout << s << " ";
});
std::cout << std::endl;
return 0;
}
运行结果:
85 92 78 90 88
💡 提示:
for_each比手写循环更简洁- 配合 lambda 表达式非常强大
3. 修改算法
(1) 3.1 copy——复制
功能: 将一个区间的元素复制到另一个区间。
示例:数组复制(难度⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst(5); // 目标容器,大小5
// 复制
std::copy(src.begin(), src.end(), dst.begin());
// 打印结果
for (int x : dst) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
(2) 3.2 transform——变换
功能: 将一个区间的元素变换后复制到另一个区间。
示例:成绩加权(难度⭐⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88};
std::vector<int> adjusted(scores.size()); // 调整后成绩
// 平时成绩占70%,考试占30%
std::transform(scores.begin(), scores.end(), adjusted.begin(),
(int s) { return s * 0.7 + 90 * 0.3; });
std::cout << "调整后成绩:";
for (int x : adjusted) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
运行结果:
调整后成绩:86.5 91.9 81.6 90 88.6
(3) 3.3 replace——替换
功能: 将容器中等于某个值的元素替换为另一个值。
示例:补考成绩处理(难度⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88};
// 将不及格的成绩(<60)替换为60(补考及格线)
std::replace_if(scores.begin(), scores.end(),
(int s) { return s < 60; },
60);
std::cout << "处理后成绩:";
for (int x : scores) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
4. 排序算法
(1) 4.1 sort——排序
功能: 对容器区间排序(默认升序)。
示例:成绩排序(难度⭐)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88};
// 升序排序
std::sort(scores.begin(), scores.end());
std::cout << "升序排序:";
for (int x : scores) {
std::cout << x << " ";
}
std::cout << std::endl;
// 降序排序
std::sort(scores.begin(), scores.end(), std::greater<int>());
std::cout << "降序排序:";
for (int x : scores) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
运行结果:
升序排序:78 85 88 90 92
降序排序:92 90 88 85 78
(2) 4.2 自定义排序规则
示例:按成绩高低排序学生(难度⭐⭐)
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
struct Student {
std::string name;
int score;
};
int main() {
std::vector<Student> students = {
{"张三", 85},
{"李四", 92},
{"王五", 78}
};
// 按成绩降序排序
std::sort(students.begin(), students.end(),
(const Student& a, const Student& b) {
return a.score > b.score;
});
std::cout << "成绩排名:" << std::endl;
for (const auto& s : students) {
std::cout << s.name << ":" << s.score << std::endl;
}
return 0;
}
运行结果:
成绩排名:
李四:92
张三:85
王五:78
5. 数值算法
(1) 5.1 accumulate——累加
功能: 计算区间内元素的累加和。
示例:计算总分(难度⭐)
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88};
// 计算总分
int total = std::accumulate(scores.begin(), scores.end(), 0);
std::cout << "总分:" << total << std::endl; // 输出:433
std::cout << "平均分:" << total / 5.0 << std::endl; // 输出:86.6
return 0;
}
(2) 5.2 内层乘积
示例:向量点积(难度⭐⭐)
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5, 6};
// 计算点积:1*4 + 2*5 + 3*6 = 32
int dot_product = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
std::cout << "向量点积:" << dot_product << std::endl; // 输出:32
return 0;
}
6. 综合示例
▶ 示例 1:成绩分析系统(难度⭐⭐⭐)
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
int main() {
std::vector<int> scores = {85, 92, 78, 90, 88, 76, 95, 83, 89, 91};
// 1. 计算总人数
int count = scores.size();
std::cout << "总人数:" << count << std::endl;
// 2. 计算总分和平均分
int total = std::accumulate(scores.begin(), scores.end(), 0);
double average = static_cast<double>(total) / count;
std::cout << "总分:" << total << ",平均分:" << average << std::endl;
// 3. 查找最高分和最低分
int max_score = *std::max_element(scores.begin(), scores.end());
int min_score = *std::min_element(scores.begin(), scores.end());
std::cout << "最高分:" << max_score << ",最低分:" << min_score << std::endl;
// 4. 统计及格人数
int passed = std::count_if(scores.begin(), scores.end(),
(int s) { return s >= 60; });
std::cout << "及格人数:" << passed << std::endl;
// 5. 排序并输出前3名
std::vector<int> top3 = scores;
std::sort(top3.begin(), top3.end(), std::greater<int>());
std::cout << "前3名:";
for (int i = 0; i < 3; i++) {
std::cout << top3[i] << " ";
}
std::cout << std::endl;
return 0;
}
输出:
85 92 78 90 88 76 95 83 89 91
运行结果:
总人数:10
总分:867,平均分:86.7
最高分:95,最低分:76
及格人数:10
前3名:95 92 91
7. 算法使用技巧
(1) 7.1 迭代器辅助函数
| 函数 | 功能 |
|---|---|
std::distance(first, last) |
计算两个迭代器之间的距离 |
std::advance(it, n) |
将迭代器前进n步 |
std::next(it) |
返回下一个迭代器 |
std::prev(it) |
返回前一个迭代器 |
(2) 7.2 Lambda表达式进阶
Lambda表达式是STL算法的好搭档:
// 基本形式
[capture](parameters) -> return_type { body }
// 示例:按多个条件排序
std::sort(students.begin(), students.end(),
(const Student& a, const Student& b) {
if (a.score != b.score)
return a.score > b.score; // 先按成绩
return a.name < b.name; // 再按姓名
});
❓ 常见问题
vector、deque):效率高 - 关联容器(set、map):有自己成员函数,用成员函数更快Q:Lambda表达式是什么? A:Lambda是C++11引入的匿名函数,可以在需要函数的地方直接定义。
基本语法:
[capture](params) -> return_type { body }
示例:
auto add = (int a, int b) { return a + b; };
std::cout << add(3, 5) << std::endl; // 输出:8
back_inserter 3. 迭代器类型不匹配 → 检查容器类型▶ 示例 3:sort排序(难度⭐)
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {5, 2, 8, 1, 9};
std::sort(v.begin(), v.end());
for (int x : v) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
输出:
1 2 3 4 5
std::sort 默认升序排序,传入迭代器范围 [begin, end)。
📖 小节
- STL算法:通用函数模板,操作容器数据
- 非修改算法:
find、count、for_each - 修改算法:
copy、transform、replace - 排序算法:
sort+ 自定义比较函数 - 数值算法:
accumulate(累加) - Lambda:匿名函数,配合算法使用
学习建议:
- 多用STL算法,少写循环
- 熟悉常用算法,查文档用不常用的
- 配合Lambda表达式,代码更简洁
📝 作业
-
**基础题 (Difficulty ⭐):创建一个 vector
<int>包含 10 个随机数,用 sort 排序后输出,再用 reverse 反转后输出。 -
**进阶题 (Difficulty ⭐⭐):用 find 在 vectorstring 中查找指定字符串,用 count 统计某个值出现的次数。
-
**挑战题 (Difficulty ⭐⭐⭐):用 remove_if 和 lambda 实现"删除 vector 中所有偶数"的操作。理解 erase-remove 惯用法。
- STL 算法操作迭代器范围,不与容器耦合
- 常用算法:sort/find/count/copy/reverse
- 算法分类:只读(find/count)、写(copy/fill)、排序(sort)
- lambda 表达式作为算法参数更简洁
- 算法+lambda 比手写循环更简洁、更安全
下一课: 实战:OOP综合(#36)—— 用面向对象思想重构学生管理系统