三路快速排序
算法概述
三路快速排序是一种改进的快速排序算法,它将数组分成三个部分:小于枢轴的部分、等于枢轴的部分和大于枢轴的部分。这样可以更高效地处理包含大量重复元素的数组。主要步骤如下:
- 选择枢轴:随机选择一个元素作为枢轴。
- 分区:将数组分成三部分:
- 小于枢轴的部分
- 等于枢轴的部分
- 大于枢轴的部分
- 递归排序:对小于枢轴和大于枢轴的部分分别进行递归排序。
算法实现
package sort
import (
"math/rand"
)
func QSort(arr []int) {
qSort(arr, 0, len(arr)-1)
}
func qSort(arr []int, l, r int) {
if l >= r {
return
}
// 随机生成枢轴下标。
// 在数组是基本有序的情况下,算法性能会退化,随机选择枢轴可以使快速排序的平均性能更接近理论上的最佳情况。
pivot := l + rand.Intn(r-l+1)
// 把枢轴的值先放在序列最左端
arr[l], arr[pivot] = arr[pivot], arr[l]
// 待排序序列分成三部分:
// arr[l + 1, lt] < v:小于枢轴的部分,刚开始是空集;
// arr[lt + 1, i - 1] == v: 等于枢轴的部分。增加这一部分,能一次把相等的部分归集在一起;
// arr[gt, r] > v: 大于枢轴的部分,刚开始是空集。
// 遍历的时候从第二个元素开始。
lt, i, gt := l, l+1, r+1
for i < gt {
if arr[i] < arr[l] {
// 小于枢轴的部分自左向右扩展了一个元素
lt++
// i 一直都 >= lt, 交换元素后,不需要判断 arr[i] 与枢轴的大小,因为已经比较过,需要跳过
arr[i], arr[lt] = arr[lt], arr[i]
i++
} else if arr[i] > arr[l] {
// 大于枢轴的部分自右向左扩展一个元素
gt--
// 交换位置后,需要判断交换后的元素 arr[i] 与枢轴的大小,所以后续不进行 i++, 以免跳过
arr[i], arr[gt] = arr[gt], arr[i]
} else {
i++
}
}
// 把枢轴放到合适的位置
arr[l], arr[lt] = arr[lt], arr[l]
// 对小于枢纽的部分进行递归排序
qSort(arr, l, lt-1)
// 对大于枢纽的部分进行递归排序
qSort(arr, gt, r)
}