参考 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
算法思想
快速排序的精髓就是分治,然后在冒泡排序的基础上递归分治。
- 从数组中挑出一个基准值
- 根据基准值重排数组,将小于基准值的元素放在前面,将大于基准值的元素放在后面,然后将基准值放在中间,这个过程成为分区(partition)
- 分别递归左右分区进行排列
动画演示
代码实现简单版(JS)
const arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
/**
* @param {Number[]} arr
* @param {Number} l
* @param {Number} r
*/
function quickSort(arr, l, r) {
if (l >= r) return
let x = l, //左指针
y = r, //右指针
base = arr[l] //取第一个元素为基准值
// partition
while (x < y) {
while (x < y && arr[y] >= base) { //从数组右边往前找到第一个小于基准值的元素
y--
}
if (x < y) { //把小于基准值的元素放到基准值左边,同时左指针向后一步
arr[x++] = arr[y]
}
while (x < y && arr[x] <= base) { //从数组左边往后找到第一个大于基准值的元素
x++
}
if (x < y) { //把大于基准值的元素放到基准值右边,同时右指针向前一步
arr[y--] = arr[x]
}
}
arr[x] = base //此时所有小于基准值的元素都在左边,大于基准值的元素都在右边
// 到这里分别递归左半边和右半边
quickSort(arr, l, x - 1)
quickSort(arr, x + 1, r)
return
}
quickSort(arr, 0, arr.length - 1)
console.log(arr) //[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
单边递归
/**
* @param {Number[]} arr
* @param {Number} l
* @param {Number} r
*/
function quickSort(arr, l, r) {
while (l < r) {
let x = l,
y = r,
base = arr[l]
while(x < y) {
while (x < y && arr[y] >= base) {
y--
}
if (x < y) {
arr[x++] = arr[y]
}
while (x < y && arr[x] <= base) {
x++
}
if (x < y) {
arr[y--] = arr[x]
}
}
arr[x] = base
quickSort(arr, x + 1, r)
r = x - 1 //减少一次递归
}
}