sort.Slice覆盖99%场景,别手写快排;其三个硬约束是:切片非nil、比较函数满足严格弱序(less(i,i)必为false)、less中不可越界访问;手写快排常见错误包括空切片取pivot panic、分区循环边界错漏、append导致原切片未修改。

sort.Slice 覆盖 99% 场景,别手写快排——除非你明确需要控制分区逻辑、调试算法过程,或在面试/教学中演示分治思想。
用 sort.Slice 替代手写快排的三个硬约束
它不是“随便传个函数就能跑”,runtime panic 往往就卡在这三条上:
-
data切片不能为nil:必须提前判空,if data == nil || len(data) == 0 { return } - 比较函数必须满足严格弱序:对任意
i,less(i, i)必须返回false;写成return a[i].X 就违规 - 切片长度变化时,
less函数里不能越界访问:比如len(a)是动态的,但你在less里硬写a[100]会 panic
手写快排时 partition 函数最常崩的三个点
崩溃不一定是 panic,更可能是排序结果错乱、无限递归、或只排了一半——问题全藏在边界处理里:
-
pivot := arr[len(arr)-1]:空切片时len(arr)是 0,len(arr)-1就是 -1,直接 panic。正确做法是函数签名带low, high int参数,用high-1取 pivot - 循环写成
for j := 0; j :当子切片长度为 1 时,<code>j从 0 开始,条件j 成立,但 pivot 没参与比较和交换,最终位置丢失 - 用
append拼左右子数组:如left := append([]int{}, ...),每次分配新底层数组,原切片完全没被修改——你看到的“排好序”只是临时副本,后续sort.Search查不到结果
递归终止条件为什么必须是 left >= right
这不是风格问题,是语义错误和越界的分水岭:
-
if left >= len(arr):第一次调用就成立(left是 0,len(arr)> 0),整个排序跳过 -
if left == right:漏掉left > right的空区间情况,在某些 pivot 选择策略下(比如 Hoare 分区未校准)可能触发无限递归 - 真实子区间是
arr[low:high],high是右开边界,所以递归参数应统一用闭区间[lo, hi]或开区间[lo, hi),并全程保持一致;混用会导致索引漂移
partition 返回的 pivot 索引对得上——差一个下标,整棵树就偏了。


















