1、概要
写到集合的末尾,就来介绍下Arrays工具类中的sort方法吧。因为Collections.sort的方法也最终调用的是Arrays.sort方法的。
Java6中sort方法默认采用的是传统快速排序,从Java7开始则使用改进版的双轴快速排序。
Java8中Arrays的排序方法只提供了两种算法的实现:
1、sort方法:双轴快速排序算法实现。
2、parallelSort方法:并行归并排序算法实现。
让我们一起来研究分析sort方法的排序吧。
2、传统快速排序算法
先来看下快速排序算法的特征吧:
1、是一种交换排序算法,即通过交换两个元素的大小来保证有序。
2、相对于其他的排序算法(冒泡排序、插入排序、希尔排序、选择排序等),平均速度最快。
3、是一个不稳定的排序算法。
快速排序基本思想
选择一个基准元素(也称为轴元素),通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
实例
在排序过程中,会首先选择第一个元素作为基准元素,并用最后一个元素作为比对的起始元素,然后利用交换及变换待比对的元素,变换规则为向基准元素的方向靠拢缩小,达到一趟扫描后确定基准元素最终位置的目的。再用递归的方式对基准元素左边和右边的子集合进行排序。
快速排序图实现
public class QuickSort {
int a[] = { 49, 38, 65, 97, 76, 13, 27, 49, 78,
34, 12, 64, 5, 4, 62, 99, 98, 54, 56,
17, 18, 23, 34, 15, 35, 25, 53, 51 };
public QuickSort() {
quick(a);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + ",");
}
}
private int getMiddle(int[] list, int low, int high) {
int tmp = list[low]; // 数组的第一个作为中轴
while (low < high) {
while (low < high && list[high] >= tmp) {
high--;
}
list[low] = list[high]; // 比中轴小的记录移到低端
while (low < high && list[low] <= tmp) {
low++;
}
list[high] = list[low]; // 比中轴大的记录移到高端
}
list[low] = tmp; // 中轴记录到尾
return low; // 返回中轴的位置
}
private void _quickSort(int[] list, int low, int high) {
if (low < high) {
int middle = getMiddle(list, low, high); // 将list数组进行一分为二
_quickSort(list, low, middle - 1); // 对低字表进行递归排序
_quickSort(list, middle + 1, high); // 对高字表进行递归排序
}
}
public void quick(int[] a2) {
if (a2.length > 0) { // 查看数组是否为空
_quickSort(a2, 0, a2.length - 1);
}
}
}
3、双轴快速排序
讲的比较清楚,也介绍了Java8中源码的实现,笔者里就不做介绍了。
主要说明两点:
1、在双轴快速排序算法中,如果数组的长度小于47,采用插入排序或成对插入排序算法实现。
2、数组长度小于286,会直接使用双轴快排。
3、如果数组中局部有序的片段比较多,则采用TimSort排序算法(一种改进的归并排序算法)。
总结
Arrays.sort主要采用双轴快速排序实现,但并非单纯的采用一种算法就解决所有的排序问题。而是根据具体的数组情况采用合适的算法来实现,例如,插入排序,TimSort排序。所以Java8中排序算法实现的复杂度,总能给我们一些启发,那就是解决一个问题不要局限于单一的方案,可以多设计出几种方案,发扬每个方案的优点,弱化各自的缺点,结合起来就是一个更好的方案。事实上,很多算法、硬件软件的设计等的演进过程就是如此。