一个更容易理解的实现,有两个注意点:
1. 分割点 pivot 如何选择?可随机或取 mid 值
2. ll
需要能尽量收缩到中点位置,防止有很多等值元素时,退化为 $O(n^2)$ 的复杂度
Ps: 虽然代码多了点,但是不容易错…
package main
import (
"bufio"
"fmt"
"os"
)
const N = 1e5 + 10
var (
in = bufio.NewReader(os.Stdin)
n int
nums [N]int
)
func main() {
fmt.Fscan(in, &n)
for i := 0; i < n; i++ {
fmt.Fscan(in, &nums[i])
}
quickSort(nums[:n], 0, n-1)
for i := 0; i < n; i++ {
fmt.Print(nums[i], " ")
}
}
func quickSort(nums []int, l, r int) {
if l >= r { return }
// 选择中间位置的值作为 pivot
mid := (l + r) >> 1
nums[l], nums[mid] = nums[mid], nums[l]
ll, rr := l, r
pivot := nums[ll]
for ll < rr {
// 注意:如果 [ll, rr] 之间数据均相等,这里可能将 ll 收缩到左断点 l
for ll < rr && nums[rr] >= pivot { rr-- }
nums[ll] = nums[rr]
for ll < rr && nums[ll] <= pivot { ll++ }
nums[rr] = nums[ll]
}
nums[ll] = pivot
// 存在相等的位置时,尽可能将 ll 收缩到二分点
for ll < mid && nums[ll+1] == pivot { ll++ }
quickSort(nums, l, ll-1)
quickSort(nums, ll+1, r)
}