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总结生成,供自己方便使用。

posted @ 2026-05-11 08:45  SDSSpJ306  阅读(20)  评论(0)    收藏  举报