Jdk的默认排序算法是什么-

72 阅读2分钟
public static void sort(int[] a) {
    DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
//  DualPivotQuicksort类的sort方法
static void sort(int[] a, int left, int right,
				 int[] work, int workBase, int workLen) {
	// Use Quicksort on small arrays
	if (right - left < QUICKSORT_THRESHOLD) {  // ①小于286,使用快排
		sort(a, left, right, true);  //见下一个代码块
		return;
	}
   ......
	/* ⑥若数组连续升降性不高,使用快排代替归并排序
	 * The array is not highly structured,
	 * use Quicksort instead of merge sort.
	 */
    ......

    private static void sort(int[] a, int left, int right, boolean leftmost) {
        int length = right - left + 1;

        // Use insertion sort on tiny arrays
        if (length < INSERTION_SORT_THRESHOLD) {  // ③小于47使用插入排序,否则使用快排

为什么小于47要用插入排序而不用冒泡排序? 双轴快排与普通快排有什么区别? 什么时候更适合使用归并排序?

冒泡排序和插入排序的时间复杂度都是 O(n2),都是原地排序算法,为什么插入排序要比冒泡排序更受欢迎呢?

我们前面分析冒泡排序和插入排序的时候讲到,冒泡排序不管怎么优化,元素交换的次数是一个固定值,是原始数据的逆序度。插入排序是同样的,不管怎么优化,元素移动的次数也等于原始数据的逆序度。

但是,从代码实现上来看,冒泡排序的数据交换要比插入排序的数据移动要复杂,冒泡排序需要 3 个赋值操作,而插入排序只需要 1 个。我们来看这段操作:

冒泡排序中数据的交换操作:
if (a[j] > a[j+1]) {   // 交换   
  int tmp = a[j];   
  a[j] = a[j+1];   
  a[j+1] = tmp;   
  flag = true;
} 
插入排序中数据的移动操作:
if (a[j] > value) {
  a[j+1] = a[j];  // 数据移动
} else { 
  break;
}

我们把执行一个赋值语句的时间粗略地计为单位时间(unit_time),然后分别用冒泡排序和插入排序对同一个逆序度是 K 的数组进行排序。用冒泡排序,需要 K 次交换操作,每次需要 3 个赋值语句,所以交换操作总耗时就是 3*K 单位时间。而插入排序中数据移动操作只需要 K 个单位时间。

这个只是我们非常理论的分析,为了实验,针对上面的冒泡排序和插入排序的 Java 代码,我写了一个性能对比测试程序,随机生成 10000 个数组,每个数组中包含 200 个数据,然后在我的机器上分别用冒泡和插入排序算法来排序,冒泡排序算法大约 700ms 才能执行完成,而插入排序只需要 100ms 左右就能搞定!

所以,虽然冒泡排序和插入排序在时间复杂度上是一样的,都是 O(n2),但是如果我们希望把性能优化做到极致,那肯定首选插入排序。插入排序的算法思路也有很大的优化空间,我们只是讲了最基础的一种。如果你对插入排序的优化感兴趣,可以自行学习一下希尔排序

// Arrays.sort()
public static <T> void sort(T[] a, Comparator<? super T> c) {
	if (c == null) {
		sort(a);
	} else {
		if (LegacyMergeSort.userRequested)
			legacyMergeSort(a, c);
		else
			TimSort.sort(a, 0, a.length, c, null, 0, 0);
	}
}

参考文档

blog.csdn.net/xlgen157387… 码出高效 极客时间 www.cnblogs.com/warehouse/p… www.jianshu.com/p/892ebd063…