这里使用的是双头并进的快速排序,做法为对于一个待排序列,首先选择一个base,也有人叫做哨兵,或者pivot等等名词。然后将小于base的值放在左边,大于base的值放在右边。然后对放在左边的数字进行快排,对放在右边的数字也进行快排。

golang源码:
func quickSort(nums []int, left, right int) {
if left < right {
mid := partition(nums, left, right)
quickSort(nums, left, mid-1)
quickSort(nums, mid + 1, right)
}
}
// 返回调整完毕之后的pivot的位置,便于之后对两边的数组进行快排
func partition(nums []int, left, right int) int {
// choose a base num
pivot := nums[left]
for left < right {
for right > left && nums[right] >= pivot {
right -= 1
}
nums[left] = nums[right]
for left < right && nums[left] <= pivot {
left += 1
}
nums[right] = nums[left]
}
//nums[left], nums[index] = nums[index], nums[left]
nums[left] = pivot
return left
}
接下来谈到优化,这里有两个基本的优化方案:
- 基准值的选择,越靠近中位数越好
- 使用为递归减少递归的层数
对于第一个我们采取三个数去中位数作为基准的方法:
func threeSumMedian(a, b, c int) int {
if a < b {
a, b = b, a
}
// a > b
if c > a {
return a
} else {
if c > b {
return c
} else {
return b
}
}
}
那么原来的快速排序中的partition就变成了这样的:
func partition(nums []int, left, right int) int {
// choose a pivot
// 改变的地方
pivot := threeSumMedian(nums[left], nums[(left+right)/2], nums[right])
//pivot := nums[left]
nums[left], pivot = pivot, nums[left]
// 改变结束
for left < right {
for pivot <= nums[right] && left < right {
right -= 1
}
nums[left] = nums[right]
for nums[left] <= pivot && left < right {
left += 1
}
nums[right] = nums[left]
}
nums[left] = pivot
return left
}
接下来我们对quicksort里面的位置采取尾递归的方式,也就是用迭代来取代递归:
func quickSort(nums []int, left, right int) {
for left < right {
mid := partition(nums, left, right)
quickSort(nums, left, mid-1)
left = mid + 1
}
}
// 改变的位置 就是把if改为for
// 然后将第二个quicksort递归改为重新赋值
最终优化完整版如下所示:
func quickSort(nums []int, left, right int) {
for left < right {
mid := partition(nums, left, right)
quickSort(nums, left, mid-1)
left = mid + 1
}
}
func partition(nums []int, left, right int) int {
// choose a pivot
// 改变的地方
pivot := threeSumMedian(nums[left], nums[(left+right)/2], nums[right])
//pivot := nums[left]
nums[left], pivot = pivot, nums[left]
// 改变结束
for left < right {
for pivot <= nums[right] && left < right {
right -= 1
}
nums[left] = nums[right]
for nums[left] <= pivot && left < right {
left += 1
}
nums[right] = nums[left]
}
nums[left] = pivot
return left
}
// input 10 20 30 ---> return 20 ; input 10 10 11 --> return 10
func threeSumMedian(a, b, c int) int {
if a < b {
a, b = b, a
}
// a > b
if c > a {
return a
} else {
if c > b {
return c
} else {
return b
}
}
}