欢迎光临
我们一直在努力

自定义排序与lamda表达式

lamda表达式

C++ 中的 Lambda 表达式(也常被称为匿名函数或Lambda 函数:说人话就是没有名字的函数)是一种用于快速定义匿名函数对象的强大特性,自 C++11 起被引入。它的核心价值在于能够就地定义简短的、一次性的函数逻辑,特别适合作为回调函数传递给标准库算法(如 std::sort, std::for_each),或在异步编程、多线程等场景中使用。

下面这个表格能帮你快速理解 Lambda 表达式的主要组成部分。

组成部分

是否必需?

作用描述与示例

捕获列表 []​

必需​

定义 Lambda 如何获取其外部作用域中的变量。例如,[x]按值捕获 x,[&y]按引用捕获 y。

参数列表 ()​

可选

和普通函数的参数列表一样,定义 Lambda 可以接受哪些参数。可以为空 ()。

可变规范 mutable​

可选

允许 Lambda 修改其按值捕获的变量的副本(注意:不影响原始变量)。通常按值捕获的变量在 Lambda 内是只读的,除非使用 mutable。

返回类型

-> type​

可选

显式指定 Lambda 的返回类型。大多数情况下,编译器可以自动推断,可省略。

函数体 {}​

必需​

包含 Lambda 要执行的实际代码。

💡 捕获列表详解

捕获列表是 Lambda 表达式的关键特性,它决定了 Lambda 函数体内能够访问和操作哪些来自外部作用域的变量。理解不同的捕获方式至关重要。

捕获方式

语法示例

效果说明

不捕获任何变量​

[]

Lambda 体内不能使用任何外部变量(全局变量等具有静态存储期的变量除外)。

按值捕获​

[x]

创建外部变量 x的一个副本供 Lambda 内部使用。在 Lambda 内部修改这个副本不影响外部的原始变量 x。

按引用捕获​

[&y]

Lambda 内部直接使用外部变量 y的引用。在 Lambda 内部修改 y会直接影响外部的原始变量。

隐式捕获(捕获所有)​

[=]或 [&]

[=]:Lambda 体内使用的所有外部变量都按值捕获。[&]:Lambda 体内使用的所有外部变量都按引用捕获。

混合捕获​

[=, &z]或 [&, x]

可以组合使用。例如 [=, &z]表示除变量 z按引用捕获外,其他使用的变量都按值捕获。

重要提醒:使用按引用捕获(特别是捕获局部变量)时,必须确保 Lambda 被调用时,所引用的变量仍然有效(即未被销毁)。否则会导致未定义行为,这是常见的错误来源。

自定义排序

在一些时候,只是使用c++自带的sort函数并不能满足我们对排序的需求,这时候就需要用到利用自定义比较函数了;

实现自定义比较函数有两种方法,一种是先把比较函数cmp定义出来,再在sort中调用:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

// 定义比较函数:降序排列
bool cmp(int a, int b) {
return a > b; // 当a>b时返回true,表示a应该排在b前面
}

int main() {
vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6};

// 使用自定义比较函数排序
sort(nums.begin(), nums.end(), cmp);

for (int num : nums) {
cout << num << " "; // 输出:9 6 5 4 3 2 1 1
}

return 0;
}

另一种就是在sort中直接定义lamda函数,进行排序:

#include <algorithm>
#include <vector>
#include <string>

struct Student {
std::string name;
int score;
int age; // 假设我们增加一个年龄字段
};

int main() {
std::vector<Student> students = {{"Alice", 85, 20}, {"Bob", 90, 19}, {"Charlie", 85, 21}};

// 使用Lambda表达式:按成绩降序,成绩相同时按年龄升序
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
if (a.score != b.score) {
return a.score > b.score; // 首先,按成绩降序
}
return a.age < b.age; // 成绩相同,则按年龄升序
});

return 0;
}

无论采用哪种方法,关键在于正确编写比较函数。它需要接受两个参数(通常是常量引用,以避免拷贝开销,对于结构体这种内存开销大的比赛时建议用引用,不然小心超时),并返回一个布尔值:

  • 返回 true:表示第一个参数应该排在第二个参数之前。

  • 返回 false:表示第一个参数不应排在第二个参数之前。

基于这个规则:

  • 若希望实现升序排序(从小到大),则当 a < b时返回 true。

  • 若希望实现降序排序(从大到小),则当 a > b时返回 true。

⚠️ 重要注意事项

  • 严格弱序:自定义的比较规则必须满足严格弱序关系。这意味着它不能产生循环逻辑,例如,如果 cmp(a, b)为 true,则 cmp(b, a)必须为 false。违反此规则会导致未定义行为。

  • 效率考虑:在比较函数中,应尽量使用常量引用(const T&)来传递参数,特别是当结构体较大时,这样可以避免不必要的值拷贝,提升效率。

  • 容器适配器:请注意,std::set、std::map、std::priority_queue等容器有它们自己的模板参数来定义排序规则,通常要求重载 <运算符或提供单独的仿函数类。

  • 赞(0)
    未经允许不得转载:171主机测评 » 自定义排序与lamda表达式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址