为何Go中调用QuickSort会修改原切片?递归相关疑问
为什么Go语言中我的快速排序会修改原切片?
这完全是Go语言切片的预期行为,不是你的代码有问题——核心原因在于切片是引用类型,和你理解的“只有传递指针才会修改原数据”的认知有偏差,咱们一步步拆解:
切片的本质:带元数据的指针
Go语言里的切片并不是直接存储数据的容器,它其实是一个包含三个字段的轻量级结构体:
- 指向底层数组的指针
- 切片当前的长度(
len) - 切片的容量(
cap)
当你把切片作为参数传递给函数时,Go会拷贝这个结构体,但结构体里的指针还是指向原来的底层数组。这意味着:函数里对切片元素的任何修改,都会直接作用在原底层数组上,自然会影响到外部的原切片。
你的两个困惑点解析
1. 为什么原变量toSort被修改了?
你调用sorting.QuickSort(toSort)时,传递的是切片结构体的副本,但这个副本里的指针和toSort指向同一个底层数组。你的QuickSort函数里直接交换了sorted切片的元素(也就是修改底层数组的内容),所以原toSort自然会看到这些修改——因为它们共享同一个数据源。
2. 为什么递归子切片操作会直接更新原sorted切片?
当你执行sorted[:curLowIndx]或sorted[curLowIndx+1:]这种子切片操作时,生成的新切片依然指向原来的底层数组,只是调整了切片的长度和范围。递归调用QuickSort处理这些子切片时,修改的还是同一个底层数组的元素,所以这些变化会直接反映到原sorted切片上。这也是你不需要合并返回子切片的原因——所有排序操作都是在同一个底层数组上完成的。
如何避免修改原切片?
如果你希望排序后不影响原切片,可以在QuickSort函数开头先创建原切片的副本,后续操作都基于这个副本:
func QuickSort(input []int) []int { if len(input) <= 1 { return input } // 创建原切片的副本,使用新的底层数组 sorted := make([]int, len(input)) copy(sorted, input) // 后续逻辑不变... pivotIndx := len(sorted) - 1 pivot := sorted[pivotIndx] curLowIndx := 0 for indx, val := range sorted { if val < pivot { sorted[indx], sorted[curLowIndx] = sorted[curLowIndx], sorted[indx] curLowIndx++ } } sorted[curLowIndx], sorted[pivotIndx] = sorted[pivotIndx], sorted[curLowIndx] QuickSort(sorted[:curLowIndx]) QuickSort(sorted[curLowIndx+1:]) return sorted }
这样修改后,原toSort就不会被改变了。
内容的提问来源于stack exchange,提问作者user6547408
相关产品推荐
相关产品推荐

