排序算法怎么选?看这几种常见场景就懂了

你有没有遇到过这样的情况:写了个程序,数据一多就卡半天?明明只是排个序,结果等得泡完一杯茶还没跑完。其实不是代码写错了,很可能是选错了排序算法

小数据量,别折腾,直接用插入排序

比如你开发一个学生成绩录入小程序,每次只处理不到 50 条记录——这时候冒泡、选择都行,但插入排序最自然。它像我们整理扑克牌一样,每来一张新成绩,就往已排好的队列里“插”到合适位置。代码短、好理解、实际跑得还快。

def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key

这种场景下,用归并或快排反而多此一举——函数调用开销、递归栈、额外空间,全是负担。

大数据量且内存充足,归并排序稳当可靠

做电商后台的同学可能深有体会:每天要对几十万条订单按下单时间重排。数据不能丢、顺序不能错、还得尽量快。这时候归并排序就很靠谱——它不依赖数据初始状态,最坏、平均、最好时间都是 O(n log n),而且稳定(相同时间的订单不会乱序)。

它适合你有一块干净内存、不怕多花点空间换确定性的场合。

内存紧张又追求速度?快排是老司机

嵌入式设备、手机 App 的本地缓存排序,经常面临内存吃紧。快排原地排序,只需要 O(log n) 的栈空间,平均性能又是所有比较排序里最快的之一。虽然最坏会退化到 O(n²),但加个随机选基准或者三数取中,基本能避开坑。

不过注意:它不稳定。如果你按价格排序,两个同价商品的原始先后关系可能被颠倒。

数据范围有限?试试计数或桶排序

比如统计某小学全年级 2000 名学生的年龄(全在 6–12 岁之间),或者给一批考试分数(0–100 分整数)排名。这时候别硬套比较排序——计数排序几行搞定,O(n + k) 时间,k 是值域大小。

def counting_sort(scores):
count = [0] * 101 # 0 到 100 共 101 个桶
for s in scores:
count[s] += 1
result = []
for i in range(101):
result.extend([i] * count[i])
return result

再比如手机号前三位分类、IP 地址段归档,桶排序也能派上大用场——把大问题拆成一堆小问题分别处理,效率翻倍。

几乎有序的数据,别忘了希尔排序

你维护一个实时日志系统,新日志总在末尾追加,偶尔需要整体重排。这时数据本身“八九不离十”,只是尾巴有点乱。希尔排序就是为这类场景生的:它先粗调,再微调,比插入排序快得多,又不像快排那样大动干戈。

一句话:排序不是炫技,而是权衡。看数据量、看内存、看是否稳定、看是否近似有序、看值域范围——选对了,程序就顺;选错了,可能上线第一天就被用户吐槽“怎么这么慢”。