快速排序是一种高级排序算法,虽然他的最优时间复杂度是O(nlogn),但是其前面的常数比其他高级排序算法要小,因此比其他高级算法要快很多。

快速排序

快速排序,Quicksort,又称分区交换排序(partition-exchange sort),简称快排,最早由东尼·霍尔提出。

快速排序通常明显比其他算法块,因为它的内部循环可以在大部分的架构上很有效率地达成。

快速排序算法执行流程:

  1. 挑选基准值:从数列中挑出一个元素,称为“基准”(pivot),
  2. 分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成,
  3. 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。

递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。

选取基准值有数种具体方法,此选取方法对排序的时间性能有决定性影响。

示意图

Sorting_quicksort_anim

使用快速排序法对一列数字进行排序的过程

快排

简单快排基本交换

快速排序法

简单快排最后交换

复杂度

复杂度
平均时间复杂度 O(nlogn)
最坏时间复杂度 O(n^2)
最优时间复杂度 O(nlogn)
空间复杂度 根据实现的方式不同而不同
稳定性 不稳定

Java实现

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class QuickSort {

public static void sort(Comparable[] arr) {
sort(arr, 0, arr.length - 1);
}

/**
* 递归对 arr[left...right] 排序
*
* @param arr 数组
* @param left 左边界
* @param right 右边界
*/
private static void sort(Comparable[] arr, int left, int right) {
if (left >= right) {
return;
}
int p = partition(arr, left, right); // 【< segment,segment,> segment】
sort(arr, left, p - 1); // 处理【< segment】部分
sort(arr, p + 1, right); // 处理【> segment】部分
}

/**
* 对 arr[left...right] 进行 partition
*
* @param arr 数组
* @param left 左边界
* @param right 右边界
*/
private static int partition(Comparable[] arr, int left, int right) {
// 选基准:此处每次选择最左边的元素
Comparable base = arr[left];

// arr[left+1...segment] < base ;arr[segment+1...i) > base
int segment = left; // j 是小于基值和大于基值的分界点
for (int i = left + 1; i <= right; i++) { // arr ==> 【segment,< segment,> segment】
// 对于比基准值小的值,放在segment所在的位置,segment索引递增
if (arr[i].compareTo(base) < 0) {
segment++;
Comparable temp = arr[i];
arr[i] = arr[segment];
arr[segment] = temp;
}
}
// 结束之后,将 base 放到 segment 位置
// 【segment,< segment,> segment】 ==> 【< segment,segment,> segment】
Comparable temp = arr[segment];
arr[segment] = arr[left];
arr[left] = temp;

// 返回基准值所在的索引
return segment;
}
}

总结

快排是东尼·霍尔提出的一种高级排序算法,主要流程有:选基准、分割、递归排序子序列三个过程。快速排序的平均和最优时间复杂度是O(nlogn),最坏时间复杂度可达O(n^2),是一种不稳定的排序算法。Java 主要排序方法为 java.util.Arrays.sort(),对于原始数据类型使用三向切分的快速排序。

参考

评论