• Collections的sort方法代码:
    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]);
}
}

这种方法的定义:<T extends Comparable<? super T>> 表示该方法中传递的泛型參数必须实现了Comparable中的compareTo(T o)方法,否则进行不了sort排序。

把这种方法细分为3个步骤:

(1)将list装换成一个对象数组

(2)将这个对象数组传递给Arrays类的sort方法(也就是说collections的sort事实上本质是调用了Arrays.sort)

(3)完毕排序之后,再一个一个地。把Arrays的元素拷贝到List中。

  • Collections方法实际是调用了Arrays的sort方法实现的,再看Arrays的sort方法代码:
    public static void sort(Object[] a, int fromIndex, int toIndex) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex);
else
ComparableTimSort.sort(a, fromIndex, toIndex);
}

注意到1.7下的sort有一个分支推断。当LegacyMergeSort.userRequested为true的情况下,採用legacyMergeSort,否则採用ComparableTimSort。

LegacyMergeSort.userRequested的字面意思大概就是“用户请求传统归并排序”的意思。这个分支调用的是与jdk1.5同样的方法来实现功能。

ComparableTimSort是改进后的归并排序,对归并排序在已经反向排好序的输入时表现为O(n^2)的特点做了特别优化。对已经正向排好序的输入降低回溯。

对两种情况(一会升序。一会降序)的输入处理比較好(摘自百度百科)。

  • legacyMergeSort代码:
    private static void legacyMergeSort(Object[] a,
int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
Object[] aux = copyOfRange(a, fromIndex, toIndex);
mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
}
  • mergeSort代码:
 private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
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 &&
((Comparable) dest[j-1]).compareTo(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);
mergeSort(dest, src, mid, high, -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 (((Comparable)src[mid-1]).compareTo(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 && ((Comparable)src[p]).compareTo(src[q])<=0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}

①:这种方法接收Object[] src,Object[] dest两个数组,依据调用它的方法能够看出仅仅须要对dest[]这个数组中的元素进行排序后。传递过来的List<T> list也即排好了序。src[]数组用来进行中介的,也即后面的方法须要调用(所以这两个数组必须区分作用)。这里有个推断条件为length < INSERTIONSORT_THRESHOLD,INSERTIONSORT_THRESHOLD为Arrays的一个常量为7,它定义了假设数组元素小于7的话就直接用swap方法排序,提高了程序的运行效率。

②:当数组元素大于7的时候,程序先将数组拆分成低区间和高区间两个区间,再调用两个递归对这两个区间元素进行排序。在递归时还得推断已经划分的区间元素是否还多于7位,假设多于7位的话继续划分成两个区间,这样循环递归调用。在这种方法中,要特别注意src[]和dest[]的參数传递位置。调用递归方法时,是将src[]数组作为排序对象进行排序。src[]排序后,在通过③或④方法将dest[]数组根据src进行排序。终于达到List<T> list排序的结果。

③:假设初始元素个数大于等于7个的话(小于7的直接在①方法排好序返回)进过②方法后。仅仅有两种情况:两个排好序的低区间和高区间。这种方法作用是:假设低区间列表中的最高元素小于高区间列表中的最低元素,则表明该次递归循环的区间段已经排好序,然后将这段数据拷贝到dest[]数组中。

反之则进入方法④。

④:进入该方法表明该次递归循环的低区间的数字最高元素大于高区间列表中的最低元素,也就是说低区间的数组元素值都大于高区间的数组元素值。因此将src中的高区间元素和低区间元素调换放入dest数组中。这样一次递归循环就调用完毕,假设还有循环就继续排序下去,否则排序就已经完毕。

static void sort(Object[] a, int lo, int hi) {
rangeCheck(a.length, lo, hi);
int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen);
return;
} /**
* March over the array once, left to right, finding natural runs,
* extending short natural runs to minRun elements, and merging runs
* to maintain stack invariant.
*/
ComparableTimSort ts = new ComparableTimSort(a);
int minRun = minRunLength(nRemaining);
do {
// Identify next run
int runLen = countRunAndMakeAscending(a, lo, hi); // If run is short, extend to min(minRun, nRemaining)
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen);
runLen = force;
} // Push run onto pending-run stack, and maybe merge
ts.pushRun(lo, runLen);
ts.mergeCollapse(); // Advance to find next run
lo += runLen;
nRemaining -= runLen;
} while (nRemaining != 0); // Merge all remaining runs to complete sort
assert lo == hi;
ts.mergeForceCollapse();
assert ts.stackSize == 1;
}

參考:

http://zoujialiang.iteye.com/blog/866902

http://blog.csdn.net/pickless/article/details/9297895

http://jxlanxin.iteye.com/blog/1814164

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Collections在sort()简单分析法源的更多相关文章

  1. 简单分析 ztree 源码

    为了把 SVG标注 代码抽成一个库,我要学习一下 ztree 是怎么写的. 开始正文. 这只是一个很简单的版本,以后可能会详细分析... (function ($) { var settings = ...

  2. FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  3. CardboardSDK-iOS 源码简单分析

    该项目地址: 地址 克隆地址为 https://github.com/rsanchezsaez/CardboardSDK-iOS.git 目前如果想在iOS设备上实现双目VR的功能,Google 已经 ...

  4. FFmpeg源码简单分析:libswscale的sws_scale()

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  5. Django-session中间件源码简单分析

    Django-session中间件源码简单分析 settings里有关中间件的配置 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddlew ...

  6. FFmpeg源码简单分析:结构体成员管理系统-AVOption

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  7. negroni-gzip源码简单分析解读

    negroni-gzip源码简单分析解读 这是一个为Negroni设计的gzip压缩处理中间件,需要用到已有的compress中的gzip,阅读了不长的源码之后,总结了一些关键要点和注意点. 检查是否 ...

  8. FFmpeg的HEVC解码器源码简单分析:概述

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  9. FFmpeg的HEVC解码器源码简单分析:解码器主干部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

随机推荐

  1. Spring学习之杂七杂八

    源码解读Spring IOC原理 - http://www.cnblogs.com/ITtangtang/p/3978349.html 1. 使用Groovy配置Bean http://blog.cs ...

  2. python2.7_1.4_将IPV4地址转换成不同的格式

    代码如下: # -*- coding: utf-8 -*- import socket from binascii import hexlify def convert_ip4_address(): ...

  3. django 基础入门(一)

    1. django 基本命令 新建project django-admin.py startproject project-name 新建app python manage.py startapp a ...

  4. django中间件templates写法

    def templates_context_process(request): from django.contrib.sites.models import Site from accounts.m ...

  5. Windows Phone 8初学者开发—第8部分:理解编译和部署

    原文 Windows Phone 8初学者开发—第8部分:理解编译和部署 第8部分:理解编译和部署 原文地址: http://channel9.msdn.com/Series/Windows-Phon ...

  6. 设置outlook自动回复

    当有同事需要出差时,或者不能即时回复邮件时,可用此功能. 下面列出设置步骤: 1.  首先,在桌面新建一个用以保存模板的文件夹,例如:emaii. 2.  新建一封邮件,输入你要自动回复的内容.另存为 ...

  7. 嵌入式:nfs挂载开发板的几个陷阱

    1. host没有设置好,这个比较容易排查到. 开启portmap帮助网络应用程序找到正确的通讯端口: 开启nfs-kernel-server服务: 开启设置要export出去的服务目录. sudo ...

  8. sqlserver 分页查询总结

    sqlserver2008不支持关键字limit ,所以它的分页sql查询语句将不能用mysql的方式进行,幸好sqlserver2008提供了top,rownumber等关键字,这样就能通过这几个关 ...

  9. BZOJ 3384: [Usaco2004 Nov]Apple Catching 接苹果( dp )

    dp dp( x , k ) = max( dp( x - 1 , k - 1 ) + *** , dp( x - 1 , k ) + *** ) *** = 0 or 1 ,根据情况 (BZOJ 1 ...

  10. [置顶] PHP调用move_uploaded_file()提示 failed to open stream: Permission denied(Linxux环境,以Ubuntu12.04为例)

    在使用PHP上传文件之后,我们有时候还需要移动到特定的文件夹,这时候就要调用move_uploaded_file()函数,可是会出现如下错误: Warning: move_uploaded_file( ...