一文读懂:C++ STL 学生与竞赛选手都会遇到的容器默认排序的疑惑
C++ STL 学生与竞赛选手都会遇到的疑惑。
下面我们系统讲清楚:
🧩 一、结论速览表:STL 常见数据结构默认排序方向
| 容器类型 | 默认排序方向 | 底层实现 | 比较器默认类型 | 改为从大到小的写法 |
|---|---|---|---|---|
std::set |
从小到大(升序) | 红黑树 | std::less<T> |
std::set<T, std::greater<T>> s; |
std::map |
从小到大(key 升序) | 红黑树 | std::less<Key> |
std::map<Key, Value, std::greater<Key>> m; |
std::multiset |
从小到大(升序) | 红黑树 | std::less<T> |
std::multiset<T, std::greater<T>> ms; |
std::priority_queue |
从大到小(最大堆) | 堆(vector+heap) | std::less<T> |
std::priority_queue<T, vector<T>, std::greater<T>> pq; |
std::sort |
从小到大(升序) | 快速排序 | std::less<T> |
std::sort(a.begin(), a.end(), greater<T>()); |
std::unordered_set / map |
无序(hash) | 哈希表 | N/A | 不支持排序 |
std::queue / stack |
无序 | 顺序容器封装 | N/A | 不支持排序 |
🧠 二、为什么 set 默认是升序,而 priority_queue 默认是降序?
(1)set / map 升序的逻辑:
- 它们的底层是红黑树(平衡二叉搜索树)。
- 为了保证查找/迭代的逻辑性,默认让中序遍历结果是从小到大。
- 所以
set<int> s;中,s.begin()指向最小值,s.rbegin()才是最大值。
➡️ 优点:
- 有序遍历自然是升序;
- 查找上界 / 下界(
upper_bound,lower_bound)逻辑统一。
(2)priority_queue 默认是最大堆(降序输出)的逻辑:
- 底层是
vector + make_heap / push_heap / pop_heap实现的二叉堆。 - 默认比较器
less<T>表示「大的优先级更高」。 - 所以
pq.top()永远返回当前最大元素。
➡️ 优点:
- 更符合“优先队列”语义:优先取出“最大优先级”元素;
- 典型应用如 Dijkstra、Huffman、Top-K 问题等。
⚙️ 三、如果要改为从大到小 / 从小到大,怎么写?
✅ 1️⃣ set / map
set<int, greater<int>> s; // 从大到小
map<int, string, greater<int>> m; // key 从大到小
✅ 2️⃣ priority_queue
默认:
priority_queue<int> pq; // 大根堆(最大值优先)
改为小根堆:
priority_queue<int, vector<int>, greater<int>> pq; // 小根堆(最小值优先)
✅ 3️⃣ sort 排序
sort(v.begin(), v.end()); // 从小到大
sort(v.begin(), v.end(), greater<>());// 从大到小
✅ 4️⃣ multiset
multiset<int, greater<int>> ms; // 从大到小排序
📦 四、举个完整例子:set 与 priority_queue 对比演示
#include <bits/stdc++.h>
using namespace std;
int main() {
set<int> s1 = {3, 1, 4, 1, 5};
set<int, greater<int>> s2 = {3, 1, 4, 1, 5};
priority_queue<int> pq1; // 大根堆
priority_queue<int, vector<int>, greater<int>> pq2; // 小根堆
for (int x : {3, 1, 4, 1, 5}) pq1.push(x), pq2.push(x);
cout << "set升序: ";
for (int x : s1) cout << x << " "; // 1 3 4 5
cout << "\nset降序: ";
for (int x : s2) cout << x << " "; // 5 4 3 1
cout << "\n大根堆: ";
while(!pq1.empty()){ cout << pq1.top() << " "; pq1.pop(); } // 5 4 3 1 1
cout << "\n小根堆: ";
while(!pq2.empty()){ cout << pq2.top() << " "; pq2.pop(); } // 1 1 3 4 5
}
💡 五、总结口诀(记忆法)
| 容器 | 默认方向 | 记忆口诀 |
|---|---|---|
set / map |
升序 | 树按中序 → 小到大 |
priority_queue |
降序(最大堆) | 优先取“大”的 → 最大堆 |
sort |
升序 | 从小排到大 |
| 改方向 | 用 greater<T> |
比较器模板换一下就行 |
记忆技巧
- 关联容器(set/map):
greater<T>实现从大到小 - 优先队列:
greater<T>实现小根堆(从小到大) - 算法函数:
greater<T>()实现从大到小排序
记住 greater 总是产生"更严格的"排序规则。

浙公网安备 33010602011771号