关闭

Collections.sort in JDK6:MergeSort

标签: 归并排序MergeSortCollections.sort
3691人阅读 评论(1) 收藏 举报
分类:
       本文是对JDK6中Collections.sort方法的源码解析,也可以看作是对Comparison method violates its general contract!的后续分析。在JDK6中,该方法底层使用的是经过优化后的归并排序,废话不多说,直接看源码。
public static <T> void sort(List<T> list, Comparator<? super T> c) {
	Object[] a = list.toArray();
	Arrays.sort(a, (Comparator)c);
	ListIterator i = list.listIterator();
	for (int j=0; j<a.length; j++) {
	    i.next();
	    i.set(a[j]);
	}
}
       将list转成数组,然后调用Arrays.sort方法排序,最后将排好顺序的值覆盖到原list上。
public static <T> void sort(T[] a, Comparator<? super T> c) {
	T[] aux = (T[])a.clone();
	if (c==null)
		mergeSort(aux, a, 0, a.length, 0);
	else
		mergeSort(aux, a, 0, a.length, 0, c);
}
       克隆一个数组,如果比较器为空,mergeSort(aux, a, 0, a.length, 0);如果比较器不为空,mergeSort(aux, a, 0, a.length, 0, c);二者内部算法实现一致,只是比较元素的方法不一样。下面来看归并排序的实现,看其是如何优化的。
private static void mergeSort(Object[] src,
				  Object[] dest,
				  int low, int high, int off,
				  Comparator c) {
	int length = high - low;

	// Insertion sort on smallest arrays
	if (length < INSERTIONSORT_THRESHOLD) {
	    for (int i=low; i<high; i++)
			for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
				swap(dest, j, j-1);
	    return;
	}

	// Recursively sort halves of dest into src
	int destLow  = low;
	int destHigh = high;
	low  += off;
	high += off;
	int mid = (low + high) >>> 1;
	mergeSort(dest, src, low, mid, -off, c);
	mergeSort(dest, src, mid, high, -off, c);

	// If list is already sorted, just copy from src to dest.  This is an
	// optimization that results in faster sorts for nearly ordered lists.
	if (c.compare(src[mid-1], src[mid]) <= 0) {
	   System.arraycopy(src, low, dest, destLow, length);
	   return;
	}

	// Merge sorted halves (now in src) into dest
	for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
		if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
			dest[i] = src[p++];
		else
			dest[i] = src[q++];
	}
}
       我们分段来看。
int length = high - low;

// Insertion sort on smallest arrays
if (length < INSERTIONSORT_THRESHOLD) {
	for (int i=low; i<high; i++)
		for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
			swap(dest, j, j-1);
	return;
}
       这里有一个常量INSERTIONSORT_THRESHOLD。
/**
 * Tuning parameter: list size at or below which insertion sort will be
 * used in preference to mergesort or quicksort.
 */
private static final int INSERTIONSORT_THRESHOLD = 7;
       当数组长度<7时,这里使用了直接插入排序。直接插入排序的过程可以看这个视频,插入排序适用于小数列的排序。这里是JDK6中归并排序的第一个优化
// Recursively sort halves of dest into src
int destLow  = low;
int destHigh = high;
low  += off;
high += off;
int mid = (low + high) >>> 1;// 中间索引,相当于(low + high) / 2
mergeSort(dest, src, low, mid, -off, c);// 排序左边
mergeSort(dest, src, mid, high, -off, c);// 排序右边
       这里开始递归排序,我们不需要关注off变量,这个变量是排序数组中部分区域的时候使用的,而我们要排序的是整个数组。
// If list is already sorted, just copy from src to dest.  This is an
// optimization that results in faster sorts for nearly ordered lists.
if (c.compare(src[mid-1], src[mid]) <= 0) {
   System.arraycopy(src, low, dest, destLow, length);
   return;
}
       左边和右边排好序之后,开始合并。这时src[low ~ mid - 1]和src[mid ~ high - 1]都是有序的,这时比较src[mid - 1]和src[mid],如果前者比后者小,那么皆大欢喜,真个src数组就是有序的了,只需将其复制到目标数组后,就完成了排序,不过这种碰运气的几率会比较小。这里是JDK6中归并排序的第二个优化
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
	if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
		dest[i] = src[p++];
	else
		dest[i] = src[q++];
}
       程序执行到这里,进行传统的合并操作。其过程如下图:
       初始状态:
       
       循环一次后:
       
       每次都比较src[p]和src[q],将较小的元素存储到dest[i],不断的循环比较,直至整个数组都有序。

       最终:
       

      JDK6中的排序是基于传统的归并排序做了部分优化,这两个优化都很简单,实际上效率并未提高多少。所以在JDK7中将其替换为TimSort,下回分解。
      (完)
      本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/42060651,转载请注明。

2
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

JDK源码解析(1)——数据数组排序:Arrays.sort()

(p.s:程序员应该多读代码,特别是前人写的代码。好的程序员对于代码应该有敏锐的“感知能力”,一看到代码就头昏眼花的,注定不是合格的程序员,更谈不上软件工程师 。。。。俺是这么认为的 。今天下载了JD...
  • octopusflying
  • octopusflying
  • 2016-08-31 19:36
  • 2329

Collections中sort()和Arrays中的sort方法分析

首先从源代码看起: 在Collections中提供的sort方法有以下有两种重载 第一个重载的定义是:> 表示该方法中传递的泛型参数必须实现了Comparable中的compareTo(T...
  • Rebirth_Love
  • Rebirth_Love
  • 2016-05-18 22:46
  • 2655

JDK不同版本的Collections.Sort方法实现

一句话总结: JDK7中的Collections.Sort方法实现中,应用了比较运算的基本属性:若A大于B,则B小于A,若A等于B,则B等于A。所以要求传入compare方法在传入参数交换时,返回值...
  • qian_348840260
  • qian_348840260
  • 2015-01-19 14:08
  • 3226

Collections中sort()方法源代码的简单分析

Collections的sort方法代码: public static void sort(List list, Comparator c) { Object[] a = list.toArra...
  • bruce_6
  • bruce_6
  • 2014-07-29 17:56
  • 3895

面试之路(16)-归并排序详解(MergeSort)递归和非递归实现

归并排序的概念及定义归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。归并排序是建立在归...
  • u010321471
  • u010321471
  • 2016-05-01 16:58
  • 3031

In-Place Merge Sort(这个描述实在太简单了,我一下子就明白了!不过这算MergeSort吗?算插入排序还差不多)

In-Place Merge Sort * If you want to avoid the space complexity required by having a scratch array,...
  • cteng
  • cteng
  • 2014-09-26 23:23
  • 965

jdk7 Collections.sort()方法报错分析

问题背景起因前些天测试给提了一个项目里的bug,在查看项目的一个在线数据的列表的时候发生了崩溃.然后我根据bugly定位发现是在使用Collection.sort()对list排序的时候产生Compa...
  • pvpheroszw
  • pvpheroszw
  • 2016-12-07 19:05
  • 318

jdk7中Arrays.sort()和Collections.sort()排序方法使用注意

1. 为什么写这篇文章 这篇文章的根源是在产品中发现了一个诡异的bug:只能在产品环境下重现,在我的本地开发环境无法重现,而双方的代码没有任何区别。最后用remotedebug的方法找到异常所在...
  • shadow_zed
  • shadow_zed
  • 2017-05-25 23:11
  • 286

insertion mergesort bubble sort 复习 python

最近重新开始复习算法那本书,整理了一下关于insertion mergesort以及 divide and conquer的思路 insertion sort is O(n^2)  best ca...
  • hyperbolechi
  • hyperbolechi
  • 2015-01-23 00:45
  • 303

java 中List排序函数Collections.sort的用法详解

List排序函数Collections.sort 1.Java提供的默认排序算法 List list = new ArrayList(); list.add(53.6); list.add...
  • XiaoXiao_Yang77
  • XiaoXiao_Yang77
  • 5天前 16:14
  • 25
    文章搜索
    个人资料
    • 访问:2328278次
    • 积分:12456
    • 等级:
    • 排名:第1323名
    • 原创:100篇
    • 转载:7篇
    • 译文:3篇
    • 评论:1089条
    详细资料
    博客专栏
    最新评论