快速排序
示意图
实现
function quickSort(arr, left, right) {
left = left !== undefined ? left : 0
right = right !== undefined ? right : arr.length - 1
if (left < right) {
const partitionIndex = partition(arr, left, right)
quickSort(arr, left, partitionIndex - 1)
quickSort(arr, partitionIndex + 1, right)
}
return arr
}
function partition(arr, left, right) {
const pivot = left;
let index = pivot + 1;
for (let i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index)
index++
}
}
swap(arr, pivot, index - 1)
return index - 1
}
function swap(arr, i, j) {
const temp = arr[j]
arr[j] = arr[i]
arr[i] = temp
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
结合示意图和代码,来了解如何分区的:
pivot
是基准(黄色),分区时要与这个数做比较,将所有数字分为比基于小的部分和比基准大的部分index
是下一个要被替换的位置,index
位置左边的数都比pivot
小- 在分区过程中,绿色表示比基准
pivot
小的,紫色表示比基准pivot
大的(第一个紫色表示index
),红色表示当前i
, - 每一次循环后,要把
pivot
与index - 1
的数互换,返回新的pivot
位置,即index - 1
如果示意图过快无法了解分区过程,可以将gif
图下载到本地,一帧一帧查看。
复杂度分析
时间复杂度
- 最好情况:每次递归都平分数组,移动需要递归
O(logn)
次,每次递归需要遍历n
次,时间复杂度为O(nlogn)
- 最差情况:每次递归都把数组分为
1
和n-1
,一共需要递归n
次,每次递归需要遍历n
次,时间复杂度为O(n^2)
- 平均时间复杂度:
O(nlogn)
空间复杂度
- 最好情况:
O(logn)
- 最差情况:
O(n)
- 平均空间复杂度:
O(logn)
注意,空间复杂度不是O(1)
,因为每次递归都在不同的函数栈里,每次递归时需要O(1)
空间,且不同函数栈里的O(1)
空间不能复用。