Lambda 表达式
一、Lambda 表达式是什么?
Lambda 表达式是 C++11 引入的匿名函数对象语法,可以在代码中直接定义一个临时的、可调用的函数。
核心价值:让你在需要使用函数的地方(如排序、二分判断、优先队列)当场编写逻辑,无需跑到远处去定义单独的函数,代码更紧凑、更易读。
二、基本语法
[捕获列表](参数列表) -> 返回值类型 { 函数体 }
| 部分 | 说明 |
|---|---|
| [捕获列表] | 指定 Lambda 内部可以访问哪些外部变量,以及方式(值/引用) |
| (参数列表) | 和普通函数一样,调用时传入的参数 |
| 返回值类型 | 可选,多数情况下编译器可自动推导 |
| 函数体 | 具体执行的代码 |
最简单的 Lambda:
auto f = []() { cout << "Hello\n"; };
f(); // 输出 Hello
带参数和返回值:
auto add = [](int x, int y) { return x + y; };
cout << add(3, 5); // 8
三、捕获列表详解
捕获列表决定了 Lambda 内部能否使用外部的变量。
3.1 捕获方式
| 写法 | 含义 |
|---|---|
| [] | 不捕获任何外部变量 |
| [x, &y] | 按值捕获 x,按引用捕获 y` |
| [=] | 按值捕获所有使用到的外部变量 |
| [&] | 按引用捕获所有使用到的外部变量 |
| [=, &x] | 默认按值捕获,但 x 按引用 |
| [&, x] | 默认按引用捕获,但 x 按值 |
| [this] | 捕获当前对象的 this 指针(成员函数内) |
3.2 值捕获 vs 引用捕获
int a = 10, b = 20;
auto f1 = [=]() { cout << a << " " << b << endl; }; // 拷贝 a, b
auto f2 = [&]() { cout << a << " " << b << endl; }; // 引用 a, b
a = 100;
f1(); // 输出 10 20(值捕获是旧值)
f2(); // 输出 100 20(引用捕获反映修改)
注意:按值捕获的变量在 Lambda 内部是只读的(除非用 mutable 修饰,但竞赛很少用)。
3.3 常见的正确写法
// 检查函数:需要读取大数组,用引用避免拷贝
auto check = [&](int mid) { ... };
// 独立比较器:只依赖参数,不捕获任何外部变量
auto cmp = [](int x, int y) { return x > y; };
// 需要修改外部计数器
int cnt = 0;
for_each(v.begin(), v.end(), [&cnt](int x) { if (x%2==0) cnt++; });
四、在算法竞赛中的典型用法
4.1 sort 自定义排序
场景:对结构体按多个字段排序。
struct Student {
string name;
int score, age;
};
vector<Student> stu = {{"Alice", 85, 18}, {"Bob", 92, 17}, {"Charlie", 85, 19}};
// 按分数降序,分数相同按年龄升序
sort(stu.begin(), stu.end(), [](const Student& a, const Student& b) {
if (a.score != b.score) return a.score > b.score;
return a.age < b.age;
});
注意:参数要用 const &,避免拷贝,且不修改原对象。
4.2 priority_queue 自定义比较
priority_queue 默认是大根堆,自定义比较时注意写法:返回 true 表示 a 的优先级低于 b。
// 小根堆:按 pair 的 second 升序
auto cmp = [](const pair<int,int>& a, const pair<int,int>& b) {
return a.second > b.second; // 注意 > 表示小根堆
};
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(cmp)> pq(cmp);
完整示例:
vector<int> nums = {3, 1, 4, 1, 5};
auto cmp = [](int a, int b) { return a > b; }; // 小根堆
priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);
for (int x : nums) pq.push(x);
while (!pq.empty()) {
cout << pq.top() << " "; // 输出 1 1 3 4 5
pq.pop();
}
4.3 二分答案的 check 函数
直接捕获数组和限制条件,代码高度集中。
// 问题:n 个物品,每个物品重量 a[i],最多 m 次操作,每次可减半。求最小可能的最大重量。
int n, m;
vector<int> a(n);
auto check = [&](int mid) {
int op = 0;
for (int x : a) {
int cnt = 0;
while (x > mid) { x /= 2; cnt++; }
op += cnt;
if (op > m) return false;
}
return true;
};
int L = 0, R = 1e9, ans = R;
while (L <= R) {
int mid = (L + R) / 2;
if (check(mid)) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
4.4 STL 算法中的谓词
vector<int> v = {1, 2, 3, 4, 5};
// 查找顺序上第一个 >3 的元素
auto it = find_if(v.begin(), v.end(), [](int x) { return x > 3; });
// 统计偶数个数
int even = count_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; });
// 检查是否全为正数
bool all_positive = all_of(v.begin(), v.end(), [](int x) { return x > 0; });
// 删除所有奇数
v.erase(remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 1; }), v.end());
4.5 作为函数参数传递(如 BFS/DFS 的状态哈希)
// 自定义哈希函数给 unordered_set 使用
auto hash = [](const pair<int,int>& p) {
return p.first * 10007 + p.second;
};
unordered_set<pair<int,int>, decltype(hash)> st(0, hash);
4.6 延迟执行(如定时器、回调)
// 模拟延迟调用
vector<function<void()>> tasks;
for (int i = 0; i < 10; i++) {
tasks.push_back([i]() { cout << "Task " << i << "\n"; });
}
for (auto& task : tasks) task();
4.7 递归 Lambda(进阶用法)
// 计算斐波那契数列
function<int(int)> fib = [&](int n) -> int {
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
};
cout << fib(10) << endl;
C++14 更高效写法(避免 std::function 开销):
auto fib = [&](auto&& self, int n) {
if (n <= 1) return n;
return self(self, n-1) + self(self, n-2);
};
cout << fib(fib, 10) << endl;
文章通过deepseek总结生成,供自己方便使用。

浙公网安备 33010602011771号