​ 在JDK1.7之前,Java在Arrays类包里使用的排序算法是快速排序,在JDK1.7之后,Arrays仍然使用快速排序,不过是从一般的快排转到了双轴快排。

快速排序

​ 快速排序是一个非常高效的排序算法,在最有时间时的O(nlogn),在最坏的情况下才是O(n * n)。但是可以通过优化选择轴线的大小,来尽可能的提高算法的效率。
在快速排序算法中,需要选择一个轴线,然后对需要排序的数组从前从后分别遍历,选择出大于轴线的值的数字放到轴线右侧,小于轴线的数字放到轴线左侧,当这一次的数组排序结束之后,进行递归的方法,分别对轴线左侧和右侧的数组进行快排的递归,直到整个数组进行排序结束。
影响快排的一个重要因素是轴线的选择,而在普通快排中,使用三数中值分割法来进行轴线的选择,提高算法效率。

双轴快排

​ 从JDK1.7起,Java在排序算法中的实现就转换成了双轴快排。
双轴快排,顾名思义,在排序的过程中采用两条轴线进行排序。选取轴线之后,先对轴线进行排序,比较出大小顺序。然后在比较过程中,将小于最小轴线的数字放到左轴线左侧,将大于最大轴线的数字放到右轴线右侧,剩余的放到两条轴线中间。同样的在划分好的三个区域内使用递归的双轴快排来对数组进行排序。
JDK中的实现:

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
static void sort(int[] a, int left, int right,
int[] work, int workBase, int workLen) {
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
int[] run = new int[MAX_RUN_COUNT + 1];
int count = 0; run[0] = left;
for (int k = left; k < right; run[count] = k) {
while (k < right && a[k] == a[k + 1])
k++;
if (k == right) break;
if (a[k] < a[k + 1]) {
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
}
if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
count--;
}
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
if (count == 0) {
return;
} else if (count == 1 && run[count] > right) {
return;
}
right++;
if (run[count] < right) {
run[++count] = right;
}
byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
int[] b;
int ao, bo;
int blen = right - left;
if (work == null || workLen < blen || workBase + blen > work.length) {
work = new int[blen];
workBase = 0;
}
if (odd == 0) {
System.arraycopy(a, left, work, workBase, blen);
b = a;
bo = 0;
a = work;
ao = workBase - left;
} else {
b = work;
ao = 0;
bo = workBase - left;
}
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
b[i + bo] = a[p++ + ao];
} else {
b[i + bo] = a[q++ + ao];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i + bo] = a[i + ao]
);
run[++last] = right;
}
int[] t = a; a = b; b = t;
int o = ao; ao = bo; bo = o;
}
}