QuickSort中打印每次分区中间状态,需在partition返回pivot索引后、递归调用前,用left/right明确界定并输出arr[left:right+1]子切片,含范围、pivot值及当前内容;避免在partition内打印或输出全数组,确保日志精准对应本次操作。

怎么在 QuickSort 里打印每次分区的中间状态
直接改递归函数,在每次 partition 执行完后,把当前子数组(含 pivot 位置)原样输出即可。关键不是“加一行 fmt.Println”,而是要确保打印的是本次分区操作作用的那块切片,而不是整个原始数组——否则会混淆边界。
常见错误是传入整个 arr 并在函数内用全局索引打印,结果输出乱序、重复或越界。正确做法是:每次递归调用时传入子切片(arr[left:right]),并在 partition 返回 pivot 索引后,立即打印该子切片当前形态。
- 用闭包或额外参数传递当前逻辑区间范围(如
left,right),避免依赖切片底层数组导致打印错位 - 打印格式建议包含:当前处理范围
[left, right)、pivot 值、分区后子切片内容 - 不要在
partition函数内部打印——它只负责重排和返回索引;打印逻辑放在排序主流程中更清晰
Go 里怎么写一个带日志的 partition 函数
标准三路或双路 partition 本身不关心日志,但你可以把它包装一层:先执行重排,再构造可读信息。注意 Go 切片是引用传递,arr[left:right] 修改会反映到底层数组,所以打印前无需深拷贝,但必须用 left/right 标定范围,否则无法对齐输出。
示例片段:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
func partition(arr []int, left, right int) int {
pivot := arr[right]
i := left - 1
for j := left; j < right; j++ {
if arr[j] <= pivot {
i++
arr[i], arr[j] = arr[j], arr[i]
}
}
arr[i+1], arr[right] = arr[right], arr[i+1]
return i + 1
}
<p>func quickSortWithTrace(arr []int, left, right int) {
if left < right {
p := partition(arr, left, right)
// 打印:当前子数组 [left, right],pivot 值为 arr[p],分区后样子
fmt.Printf("partition [%d,%d]: pivot=%d → %v\n",
left, right, arr[p], arr[left:right+1])
quickSortWithTrace(arr, left, p-1)
quickSortWithTrace(arr, p+1, right)
}
}-
arr[left:right+1]是为了包含right位置(因right是闭区间 pivot 下标) - 如果用开区间习惯(
right表示上界不包含),则统一用arr[left:right],且调用时传len(arr)而非len(arr)-1 - 避免在
partition内部修改arr后立刻fmt.Println(arr)——它会输出整个底层数组,不是你期望的子段
为什么用 fmt.Printf 而不是 log 包
纯调试阶段,fmt.Printf 更轻量、无缓冲、输出顺序确定;log 默认带时间戳和前缀,干扰观察分区节奏。而且 log 的输出可能被缓冲(尤其重定向到文件时),导致步骤顺序错乱。
- 若需开关日志,用一个全局布尔变量
traceEnabled控制是否执行fmt.Printf行,比换包更直接 - 不用
log.SetOutput(ioutil.Discard)动态关日志——增加复杂度,且仍绕不开缓冲问题 - 如果后续要导出为机器可读格式(如 JSON 步骤流),那就该自己定义结构体并序列化,而非依赖
log或fmt
容易被忽略的边界:递归终止前的最后一次打印
当 left == right 时,子数组长度为 1,partition 不会触发(因循环条件 j 不成立),也不会进入递归,但很多人会误以为这里该打印“已有序”。其实不该——分区过程只发生在长度 ≥2 时。真正该关注的是:当 <code>right - left == 1(即两个元素),partition 会执行一次完整交换逻辑,并输出该二元组的状态。
- 测试时务必用
[]int{3,1,4,1,5}这类含重复值的输入,验证 pivot 位置和相等元素的落点是否符合预期 - 如果发现某次分区后子切片没变化(比如全相等),那是正常的——
partition仍返回了 pivot 索引,只是左右没交换而已 - 输出行数 = 实际发生的分区次数,等于递归树中非叶子节点数量,不是数组长度

















