std::ranges::sort 是 C++20 引入的 Ranges(范围)算法。它不仅是老版本 std::sort 的语法糖,还引入了非常强大的 投影(Projections) 功能。
1. 语法对比:老版本 vs C++20
老版本 std::sort
必须显式传递迭代器(头和尾):
std::sort(v.begin(), v.end());
C++20 std::ranges::sort
直接传递整个容器(Range):
std::ranges::sort(v);
优点: 更简洁,避免了
v.begin(), v.end()这种冗长的写法,也减少了传错容器(比如std::sort(v1.begin(), v2.end()))的风险。
2. 核心神器:投影 (Projections)
这是 ranges::sort 最牛的地方。它的完整函数签名(简化版)如下:
std::ranges::sort(range, comparator, projection)
- 参数 1 (Range): 要排序的容器。
- 参数 2 (Comparator): 比较规则,默认是
std::less{}(从小到大)。 - 参数 3 (Projection): 投影。在进行比较之前,先对元素进行一个“变换”或“提取”。
详解你的代码:
ranges::sort(meetings, {}, [](auto& a) { return a[2]; });
meetings: 待排序的二维向量。{}: 占位符,表示使用默认比较器(即<)。[](auto& a) { return a[2]; }: 这是投影函数。- 它告诉
sort:“不要直接比较两个 vectora和b,而是先取它们的a[2]和b[2],然后比较这两个数字。”
- 它告诉
如果没有投影,老版本的写法是:
std::sort(meetings.begin(), meetings.end(), [](const vector<int>& a, const vector<int>& b) {return a[2] < b[2]; // 比较规则写在这里
});
使用了投影后: 比较规则(升序)和“提取字段”(取下标 2)分开了,逻辑更清晰。
3. 常见用法示例
场景 A:对结构体排序
假设有一个 Student 结构体,你想按分数排序:
struct Student {string name;int score;
};
vector<Student> students;// 只需要传入成员指针作为投影即可,极其简洁!
std::ranges::sort(students, {}, &Student::score);
场景 B:降序排序
想按分数从高到低排序:
std::ranges::sort(students, std::ranges::greater{}, &Student::score);
4. 为什么要在算法题里用它?
- 代码量少: 省去了大量的
.begin()和.end()。 - 性能无损: 它在底层依然是快速排序/堆排序/插入排序的组合(Introsort),效率和
std::sort一样,都是 $O(n \log n)$。 - 可读性高: 尤其是处理复杂嵌套容器(如
vector<vector<int>>)时,投影功能让代码意图一眼就能看明白。