quicksort 是原地排序函数,递归实现:若长度≤1则返回;选首元素为 pivot,分区后递归排序左右子数组。

Go 里手写 quicksort 最简可行版本
直接上能跑、不依赖标准库、边界处理正确的实现:
func quicksort(arr []int) {
if len(arr) func partition(arr []int) int {
pivot := len(arr) - 1
i := 0
for j := 0; j <p>这个版本用末尾元素当基准,原地分区,递归切片——注意 <code>arr[:pivot]</code> 和 <code>arr[pivot+1:]</code> 是切片操作,不是新分配数组,性能关键就在这。</p><h3>为什么不能直接传 <code>[]int</code> 进去排序?</h3><p>Go 切片是引用类型但底层数组指针不可变,函数内重赋值不会影响调用方。你必须原地改元素,而不是试图 <code>arr = append(...)</code> 或 <code>arr = sort.Ints(...)</code> 那种“换底层数组”的操作。</p>
- 错误写法:
arr = append([]int{}, arr...)→ 新建底层数组,原切片没变 - 正确思路:所有交换、移动都发生在原
arr的元素索引上 - 递归调用时传子切片(如
arr[lo:hi])没问题,因为共享底层数组
partition 函数里 i 和 j 的初始值和边界容易错
常见崩溃或逻辑错:越界、漏比较、基准没归位。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
j必须从0跑到pivot-1(不包含基准),否则会把基准自己也比一遍 -
i从0开始,代表“ - 如果用首元素当基准,得先把它挪到末尾再分区,否则
arr[0]被覆盖后找不回来 - 空切片或单元素切片必须提前
return,否则len(arr)-1会是负数
实际项目里别真手写 quicksort
Go 标准库 sort.Slice 底层就是优化过的 introsort(快排 + 堆排 + 插入排序混合),对小数组自动切到插入排序,深度过深自动切堆排防退化。
- 手写版在随机数据下表现接近,但最坏 O(n²) 没防护
- 没有三数取中或随机选基准,遇到已排序数组会卡死
- 泛型支持要自己写类型参数,而
sort.Slice只要提供比较函数就行 - 真要调试排序行为,加日志比改手写逻辑快得多
除非你在写算法题、教学 demo,或者明确知道数据特征(比如极短数组、特定分布),否则直接用 sort.Slice。
最常被忽略的点:手写时忘了切片是引用传递但长度/容量可变,arr[:n] 看似安全,但若原切片后面还有数据,partition 过程中可能意外读到脏值——务必确保传入的是干净子切片,或一开始就复制一份。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










