稳定排序(Stable Sort) 是指在排序过程中,相等元素的相对顺序保持不变的排序算法。换句话说,如果原始序列中有两个元素 A 和 B 满足 A == B,且 A 原本在 B 之前,那么在排序后的序列中,A 仍然会在 B 之前。
稳定排序的核心特点
-
相等元素的顺序不变:
- 例如,原始序列:
[ (Alice, 25), (Bob, 20), (Charlie, 25) ](按姓名和年龄存储)。 - 如果先按年龄升序排序,再按姓名升序稳定排序,结果会是:
[ (Bob, 20), (Alice, 25), (Charlie, 25) ]- 年龄相同的
Alice和Charlie的相对顺序与原始序列一致(Alice在前)。
- 年龄相同的
- 例如,原始序列:
-
非稳定排序可能改变顺序:
- 如果使用非稳定排序(如
std::sort),年龄相同的Alice和Charlie的顺序可能被交换:[ (Bob, 20), (Charlie, 25), (Alice, 25) ]
- 如果使用非稳定排序(如
为什么需要稳定排序?
稳定排序在以下场景中非常重要:
-
多关键字排序:
- 例如,先按“部门”排序,再按“工资”稳定排序。这样能保证同一部门的员工按工资排序后,原始顺序(如入职时间)不会被破坏。
- 示例:
struct Employee { std::string dept; int salary; int id; // 入职编号 }; std::vector<Employee> employees = { {"HR", 5000, 101}, {"IT", 7000, 201}, {"HR", 6000, 102}, {"IT", 6000, 202} }; // 先按部门升序,再按工资升序(稳定排序保证同部门同工资的顺序不变) std::stable_sort(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) { return a.dept < b.dept; // 先按部门排序 }); std::stable_sort(employees.begin(), employees.end(), [](const Employee& a, const Employee& b) { return a.salary < b.salary; // 再按工资稳定排序 }); // 结果: // [ ("HR", 5000, 101), ("HR", 6000, 102), ("IT", 6000, 202), ("IT", 7000, 201) ] // 注意:同部门同工资的顺序(如 HR 的 101 和 102)保持不变。
-
保留原始顺序的场景:
- 例如,对日志按时间戳排序,但希望相同时间戳的日志按原始输入顺序输出。
稳定排序 vs 非稳定排序
| 特性 | 稳定排序 | 非稳定排序 |
|---|---|---|
| 相等元素顺序 | 保持不变 | 可能改变 |
| 典型算法 | 归并排序、插入排序、冒泡排序 | 快速排序、堆排序、选择排序 |
| STL 实现 | std::stable_sort | std::sort |
| 时间复杂度 | 通常 O(N log N)(归并排序) | 平均 O(N log N),最坏 O(N²) |
| 空间复杂度 | 可能需要额外空间(如归并排序) | 通常原地排序(如快速排序) |
STL 中的稳定排序
在 C++ STL 中,std::stable_sort 是稳定排序的实现,而 std::sort 是非稳定的。
示例对比:
#include <iostream>
#include <vector>
#include <algorithm>
struct Item {
int value;
int id; // 原始顺序标识
};
int main() {
std::vector<Item> items = {
{3, 1}, {1, 2}, {2, 3}, {1, 4} // 两个 value=1 的元素,id 分别为 2 和 4
};
// 非稳定排序(std::sort)
std::sort(items.begin(), items.end(), [](const Item& a, const Item& b) {
return a.value < b.value;
});
// 可能输出:{1,4}, {1,2}, {2,3}, {3,1} (id=4 和 id=2 的顺序可能交换)
// 稳定排序(std::stable_sort)
std::stable_sort(items.begin(), items.end(), [](const Item& a, const Item& b) {
return a.value < b.value;
});
// 保证输出:{1,2}, {1,4}, {2,3}, {3,1} (id=2 始终在 id=4 之前)
for (const auto& item : items) {
std::cout << "(" << item.value << ", " << item.id << ") ";
}
return 0;
}
总结
- 稳定排序:相等元素的相对顺序不变,适用于多关键字排序或需要保留原始顺序的场景。
- 非稳定排序:不保证相等元素的顺序,但通常更快(如
std::sort)。 - STL 选择:
- 需要稳定性时用
std::stable_sort。 - 仅需快速排序时用
std::sort。
- 需要稳定性时用

2713

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



