1. 概述

本文将介绍什么是稳定排序算法,以及它在实际开发中的应用场景。同时我们也会分析排序稳定性在哪些场景下是必须考虑的,哪些场景下可以忽略。

2. 排序算法中的稳定性

排序算法的“稳定性”指的是:当待排序的数据中存在多个相等的元素时,排序算法是否会保持它们原有的相对顺序

  • ✅ 稳定排序:相等元素在排序后的相对顺序不变
  • ❌ 不稳定排序:相等元素之间的顺序可能被打乱

举个例子:

我们有数组 A = [5, 8, 9, 8, 3],其中有两个 8。如果我们能通过排序算法得到 [3, 5, 8, 8, 9],并且两个 8 的相对顺序没有变化,那这个排序算法就是稳定的。

下面这张图可以更直观地帮助我们理解:

Stable vs Unstable 1

如图所示,稳定排序保留了两个相同值(8)的原始顺序,而不稳定排序可能会打乱它们的顺序。

3. 稳定性何时重要?

3.1 稳定性适用的场景

并不是所有排序场景都需要稳定性。只有在以下情况下,稳定性才显得重要:

  • 数据中存在可区分的相等元素
  • 数据本身已经部分有序,排序操作需要保留原有顺序

举个实际例子:假设我们正在统计一篇文章中各个单词的出现频率,并希望按频率排序。如果多个单词频率相同,我们希望它们按字母顺序排列。

3.2 实例说明:单词频率排序

第一步:统计单词频率

输入文本:

how much wood would woodchuck chuck if woodchuck could chuck wood

输出结果:

how       1  
much      1  
wood      2  
would     1  
woodchuck 2  
chuck     2  
if        1  
could     1

第二步:先按字母顺序排序,再按频率排序

第一次排序(按字母顺序):

(chuck, 2)
(could, 1)
(how, 1)
(if, 1)
(much, 1)
(wood, 2)
(woodchuck, 2)
(would, 1)

第二次排序(按频率,使用不稳定排序):

(wood, 2)
(chuck, 2)
(woodchuck, 2)
(could, 1)
(how, 1)
(if, 1)
(would, 1)
(much, 1)

⚠️ 问题来了:使用不稳定排序后,三个频率为 2 的单词顺序被打乱了,不再保持字母顺序。

如果我们使用稳定排序来按频率排序,结果如下:

(chuck, 2)
(wood, 2)
(woodchuck, 2)
(could, 1)
(how, 1)
(if, 1)
(much, 1)
(would, 1)

✅ 可以看到,频率相同的单词之间仍然保持了字母顺序。

3.3 基数排序(Radix Sort)与稳定性

基数排序(Radix Sort) 是一种非比较型排序算法,依赖于稳定排序的子过程(通常是计数排序)。

它的工作流程如下:

for 每一位数字 k(从最低位到最高位):
  使用计数排序对当前位进行排序

radix stable

✅ 正是因为每轮排序都使用了稳定的子排序算法(如计数排序),Radix Sort 才能保证最终结果的正确性。比如在对十位数排序时,虽然 9881 向下移动了,但它仍然保持在 9888 的前面。

4. 常见排序算法的稳定性分类

下面是一些常见排序算法的稳定性分类:

排序算法 稳定性
Merge Sort ✅ 稳定
Timsort ✅ 稳定
Counting Sort ✅ 稳定
Insertion Sort ✅ 稳定
Bubble Sort ✅ 稳定
Quicksort ❌ 不稳定
Heapsort ❌ 不稳定
Selection Sort ❌ 不稳定

⚠️ 注意:某些不稳定排序算法也可以通过修改实现稳定排序,比如在 Quicksort 中使用额外信息来记录原始顺序。

5. 总结

  • ✅ 稳定排序保留相等元素之间的原始顺序
  • ❌ 不稳定排序可能会打乱这些元素的顺序
  • 📌 在需要保留数据原有顺序的场景中(如多字段排序、Radix Sort),稳定性非常重要
  • 🧠 多数排序算法的稳定性是其固有属性,但也有些可以通过改造实现稳定

理解排序算法的稳定性,有助于我们在实际开发中选择合适的排序策略,避免“踩坑”。


原始标题:Stable Sorting Algorithms

« 上一篇: Quicksort 算法概述