作用
使数组有序
原理
快排通过递归的方式,来完成对数组的排序,在每一轮中:
- 选取一个基准值(
pivot) - 将所有小于它的元素放到左边,将所有大于它的元素放到右边
- 对于左部分和右部分分别递归
分析
通过上述步骤,我们可以发现,快排实际上会讲数组不断地去划分成更小的区间,由此抛出一个问题,如果数组天然有序,那么是不是我们快排的复杂度实际上和冒泡一样?
为了解决这个问题,我们需要采取一定的优化,为此我们需要用插入排序为快排做优化,另外对于一个快排的区间我们设置为最小 16
优化
我们对于一个数组,首先用快排将它分区,最小分到 16 个为一组,那么组和组之间是相对有序的,每个组的组内元素也是相对有序的
对于每一组元素,我们用插入排序来使它有序,由此降低了快排的复杂度
对于快排,我们用单边快排的方法(对右半部分做递归,左边只做迭代),降低空间复杂度
代码
function quick_sort_V3(arr, l, r) {
quickSort(arr, l, r)
final_insert_sort(arr, l, r)
}
const THRESHOLD = 16
const getMid = (a, b, c) => {
if (a > b) return getMid(b, a, c)
if (a > c) return getMid(c, b, a)
if (b > c) return getMid(a, c, b)
return a
}
function quickSort(arr, l, r) {
while (r - l > THRESHOLD) {
let x = l,
y = r,
base = getMid(arr[l], arr[Math.floor((l + r) / 2)], arr[r]) // make sure it's not the min or max
do {
while (arr[x] < base) x++
while (arr[y] > base) y--
if (x <= y) {
// swap
;[arr[x], arr[y]] = [arr[y], arr[x]]
x++
y--
}
} while (x <= y)
// quick sort on right side
quickSort(arr, x, r)
r = y
}
}
// insert sort to handle < 16 scenario
function final_insert_sort(arr, l, r) {
let ind = l
// get index of the min value item
for (let i = l + 1; i <= r; i++) {
if (arr[i] < arr[ind]) ind = i
}
// swap along until the min value get to l
while (ind > l) {
;[arr[ind], arr[ind - 1]] = [arr[ind - 1], arr[ind]]
ind--
}
// insert sort
// due to the leftmost is already an sorted one, we start from the 2th index
for (let i = l + 2; i <= r; i++) {
let j = i
while (arr[j] < arr[j - 1]) {
;[arr[j], arr[j - 1]] = [arr[j - 1], arr[j]]
j--
}
}
}