头文件:<algorithm>
一句话:对 [first, last) 左闭右开区间排序。
C++11 之后标准规定:sort 是不稳定排序,实现一般是 introsort(内省排序 = 快速排序 + 堆排序 + 插入排序三者结合)。时间复杂度:$O(N \log N)$。
一、函数原型
1 2 3 4 5 6 7
| template< class RandomIt > void sort( RandomIt first, RandomIt last );
template< class RandomIt, class Compare > void sort( RandomIt first, RandomIt last, Compare comp );
|
⚠️ 区间是 [first, last)——包含 first,不包含 last。数组/vector 排序一般写 sort(a.begin(), a.end())。
二、基础示例
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream> #include <vector> #include <algorithm> using namespace std;
int main() { vector<int> v = {5, 2, 9, 1, 5, 6}; sort(v.begin(), v.end()); for (auto x : v) cout << x << " "; return 0; }
|
三、降序排序:三种写法
1 2 3 4 5 6 7 8 9 10 11 12 13
| vector<int> v = {5, 2, 9, 1};
sort(v.begin(), v.end(), greater<int>());
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
sort(v.begin(), v.end()); reverse(v.begin(), v.end());
|
四、自定义比较函数 cmp
比较函数语义:cmp(a, b) = true 代表 a 应该排在 b 前面。
- 升序:
return a < b;
- 降序:
return a > b;
4.1 结构体排序
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct Node { int x, y; };
int main() { vector<Node> arr = {{3, 1}, {1, 5}, {2, 2}}; sort(arr.begin(), arr.end(), [](const Node& a, const Node& b) { if (a.x != b.x) return a.x < b.x; return a.y > b.y; }); return 0; }
|
4.2 ⚠️ 严格弱序:cmp 必须遵守的硬规则
| 规则 |
错误写法 |
后果 |
cmp(a, a) = false |
写成 <= 或 >= |
未定义行为,程序可能崩溃 / 乱序 |
| 不能矛盾 |
cmp(a,b)=true 同时 cmp(b,a)=true |
同上 |
| 传递性 |
cmp(a,b) 且 cmp(b,c) → 必须 cmp(a,c) |
同上 |
✅ 正确:return a < b; 或 return a > b;
❌ 错误:return a <= b;
1 2 3 4 5
| sort(v.begin(), v.end(), [](int a, int b) { return a < b; });
sort(v.begin(), v.end(), [](int a, int b) { return a <= b; });
|
五、stable_sort:保留相等元素原顺序
|
std::sort |
std::stable_sort |
| 稳定性 |
❌ 不稳定 |
✅ 稳定 |
| 底层 |
introsort(快排 + 堆排 + 插入) |
归并排序 |
| 复杂度 |
$O(N \log N)$ |
$O(N \log N)$,常数更大、内存开销更高 |
| 场景 |
默认选它 |
要求"相等元素保持原顺序" |
蓝桥杯 / 洛谷常见的"次级排序"题,比如「先按分数排,分数相同按名字字典序」——其实直接写 cmp 一次拍好就行,多数情况用不上 stable_sort。
六、适用迭代器
sort 只支持随机访问迭代器:
| 容器 |
能否直接 sort |
vector / array / 普通数组 |
✅ |
deque |
✅ |
list |
❌(自带 .sort() 成员函数,是稳定排序) |
set / map |
❌(本身就是有序的,不需要 sort) |
1 2 3
| int a[10] = {3, 1, 4, 2}; sort(a, a + 4);
|
七、pair / tuple 排序
pair 默认先比较 first,相等再比较 second,自带字典序,直接丢进 sort:
1 2 3
| vector<pair<int, int>> vp = {{2, 5}, {1, 9}, {2, 3}}; sort(vp.begin(), vp.end());
|
tuple 同样自带字典序,可以直接排序(见 STL 笔记里的 tuple 一节)。
八、竞赛常见套路
8.1 多关键字排序
写一个 cmp 一次性排好,比如:
1 2 3 4 5
| sort(arr.begin(), arr.end(), [](const Node& a, const Node& b) { if (a.x != b.x) return a.x < b.x; return a.y > b.y; });
|
8.2 排序 + 二分
排序后用 lower_bound / upper_bound 在 $O(\log N)$ 内查找:
1 2
| sort(v.begin(), v.end()); auto it = lower_bound(v.begin(), v.end(), 5);
|
8.3 离散化
把大数据范围映射到小下标时,先 sort + unique + erase:
1 2
| sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());
|
九、易错点清单
cmp 写成 <= / >=:破坏严格弱序,UB 行为。只用 < 或 >。
- 左闭右开区间写错:
sort(a.begin(), a.end()) 才是排序整个数组,写成 end() - 1 会漏掉最后一个元素。
list / set 直接 sort:编译报错。list.sort() 是成员函数;set / map 本来有序,不需要 sort。
- 大量数据忘记配
ios::sync_with_stdio(false):sort 本身够快,但前面读入慢,整体超时。
- 结构体里
operator< 没用 const:会导致 set / map / sort 报错或拷贝。
- 期望稳定却用
sort:相同值原顺序会变——用 stable_sort。
十、极简速记
| 需求 |
写法 |
| 默认升序 |
sort(v.begin(), v.end()); |
| 降序 |
sort(v.begin(), v.end(), greater<int>()); |
| 自定义排序 |
sort(v.begin(), v.end(), cmp); |
| 稳定排序 |
stable_sort(v.begin(), v.end()); |
| 普通数组 |
sort(a, a + n); |
十一、小结
std::sort 默认 introsort,$O(N \log N)$,不稳定;
- 区间
[first, last) 左闭右开,别漏元素;
- 自定义
cmp 用 < 或 >,千万别写 <= / >=;
pair / tuple 自带字典序,直接 sort;
- 普通数组 /
vector / deque 可用,list 用成员 .sort()。