在STL 中, std::sort 是最常用的排序算法之一。位于 <algorithm> 头文件中,提供了一个极其高效且灵活的排序方案。
对于绝大多数应用场景,只需要掌握 std::sort 的两种用法。
std::sort 的基本信息
- 头文件: 必须包含
#include <algorithm>。 - 作用: 对一个范围内的元素进行排序。
- 特点:
- 速度快: 平均时间复杂度为 O(nlog(n))。
- 不稳定排序: 对于值相等的元素,排序后它们的相对位置不保证与排序前一致。如果需要保持相对位置,请使用
std::stable_sort。 - 通用性强: 它可以排序
std::vector,std::array,std::deque,甚至是普通的 C 风格数组。
一、默认排序(升序)
这是 std::sort 最基本、最常见的用法。不需要任何额外的参数,默认会将范围内的元素按照从小到大的顺序(非降序)排列。
std::sort 接受两个参数:
first: 指向待排序范围的第一个元素的迭代器。last: 指向待排序范围的最后一个元素的下一个位置的迭代器。
这是一个非常重要的“左闭右开”区间 [first, last) 的概念,在 STL 中非常普遍。
示例:对整数 vector 进行升序排序
#include <iostream>
#include <vector>
#include <algorithm> // 别忘了包含这个头文件
std::vector<int> numbers = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
// 调用 std::sort 进行默认升序排序
std::sort(numbers.begin(), numbers.end());
二、自定义排序
std::sort 还可以通过提供第三个参数——比较函数(Comparator),实现自定义排序。
这个比较函数本质上是一个回答“谁应该排在前面?”问题的函数。它的规则非常简单:
比较函数 comp(a, b) 必须返回一个 bool 值。如果返回 true,则意味着 a 应该排在 b 的前面;如果返回 false,则 b 应该排在 a 的前面(或保持相对位置)。
方式 1:使用普通函数(降序排序)
这是最直观的方式,我们可以定义一个独立的函数来实现降序排序。
#include <iostream>
#include <vector>
#include <algorithm>
// 比较函数:如果 a 大于 b,则 a 应该排在前面
bool compare_desc(int a, int b) {
return a > b;
}
int main() {
std::vector<int> numbers = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
std::sort(numbers.begin(), numbers.end(), compare_desc);
for (int num : numbers) {
std::cout << num << " "; // 输出: 9 8 7 6 5 4 3 2 1 0
}
std::cout << std::endl;
}
方式 2:使用 Lambda 表达式(现代 C++ 推荐)
在 C++11 及以后,使用 Lambda 表达式是定义临时比较逻辑最简洁、最流行的方式。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
// 使用 Lambda 表达式实现降序排序
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b;
});
for (int num : numbers) {
std::cout << num << " "; // 输出: 9 8 7 6 5 4 3 2 1 0
}
std::cout << std::endl;
}
方式 3:排序自定义结构体
假设我们有一个学生结构体,需要根据学生的分数进行排序。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
struct Student {
std::string name;
int score;
};
int main() {
std::vector<Student> students = {
{"张三", 95},
{"李四", 88},
{"王五", 100},
{"赵六", 95}
};
// 使用 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.name < b.name;
});
std::cout << "按分数降序排序后:" << std::endl;
for (const auto& s : students) {
std::cout << "姓名: " << s.name << ", 分数: " << s.score << std::endl;
}
}
输出:
按分数降序排序后:
姓名: 王五, 分数: 100
姓名: 张三, 分数: 95
姓名: 赵六, 分数: 95
姓名: 李四, 分数: 88
总结
- 简单升序:
std::sort(v.begin(), v.end()); - 自定义排序:
std::sort(v.begin(), v.end(), my_comparator); - 比较器核心:
comp(a, b)返回true意味着a排在b前面。 - 现代首选: 优先使用 Lambda 表达式来编写自定义比较器,尤其是在处理复杂对象时。
顺带一提stable_sort
核心区别:稳定性
稳定性是 stable_sort (稳定排序) 和 sort (不稳定排序) 的唯一但至关重要的区别。
-
不稳定排序 (
std::sort): 当两个元素 A 和 B 在排序规则下被视为“相等”时(例如,两个学生分数都是 95),std::sort不保证 它们在排序后的相对位置与排序前一致。如果 A 原本在 B 前面,排序后 B 完全有可能跑到 A 的前面。 -
稳定排序 (
std::stable_sort): 当元素 A 和 B 被视为“相等”时,stable_sort保证 如果 A 在原始序列中位于 B 的前面,那么在排序后的序列中,A 依然会位于 B 的前面。
std::stable_sort 的使用方法和 std::sort 完全一样!
它同样接受两个(用于默认升序)或三个(用于自定义比较)参数。
// 默认升序稳定排序
std::stable_sort(v.begin(), v.end());
// 使用自定义比较函数进行稳定排序
std::stable_sort(v.begin(), v.end(), my_comparator);
为 std::sort 编写的任何比较函数或 Lambda 表达式,都可以无缝地用于 std::stable_sort。
性能权衡
为了维持稳定性,stable_sort 的算法实现通常比 sort 更复杂。在最坏的情况下,它可能需要分配额外的内存(比如典型的归并排序实现)。因此,std::stable_sort 的运行速度可能会比 std::sort 稍慢,并且可能消耗更多内存。
一般情况下用sort,有明确稳定排序需求时再用stable_sort
sort与stable_sort详解
7760

被折叠的 条评论
为什么被折叠?



