直接回答:Python 的 sorted() 和 list.sort() 用的是 Timsort——Tim Peters 2002 年专为 CPython 设计的混合算法,结合了归并排序和二分插入排序,最坏时间复杂度 O(n log n),对现实中常见的"部分有序"数据能接近 O(n)。它稳定:相等元素的相对顺序排序后保持不变。Java 的对象数组排序、Android 运行时也采用了同一算法。
展开解析:核心流程分三步。第一,从左到右扫描出天然有序的 run(连续递增段直接利用,严格递减段原地反转后利用);第二,如果 run 太短(小于 minrun,根据数组长度取 32–64 之间),用二分插入排序把它扩充到 minrun,因为小规模数据上插入排序常数最小;第三,把 run 压入栈,并维护两条不变式(栈顶三个 run 的长度满足 A > B + C 且 B > C),不满足时按规则归并相邻 run。归并时用 galloping(疾跑)模式:发现一段连续元素都小于另一段时切换为指数搜索批量搬运,减少逐个比较的开销。
稳定性的来源:归并时左右两段元素相等时优先取左段(先出现者),所以相等键不交换顺序。配合 key 函数(每个元素只计算一次键值,等价于装饰-排序-反装饰模式),可以实现多级排序:先按次要键排,再按主要键排,稳定性保证次要键的顺序不被打乱,无需写复杂的组合比较器。
实践要点:sorted() 返回新列表、list.sort() 原地且返回 None;reverse=True 不是靠反转结果实现的,而是调整比较方向,依然稳定;functools.cmp_to_key 只用于兼容老式比较函数。
追问方向:minrun 为什么取 32–64?galloping 在什么数据分布下会退化?
(约 540 字)