`

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

阅读更多
  • Collections的sort方法代码:
[java] view plain copy
 
 print?
  1. public static <T> void sort(List<T> list, Comparator<? super T> c) {  
  2.     Object[] a = list.toArray();  
  3.     Arrays.sort(a, (Comparator)c);  
  4.     ListIterator i = list.listIterator();  
  5.     for (int j=0; j<a.length; j++) {  
  6.         i.next();  
  7.         i.set(a[j]);  
  8.     }  
  9. }  

这个方法的定义:<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方法代码:
[java] view plain copy
 
 print?
  1. public static void sort(Object[] a, int fromIndex, int toIndex) {  
  2.     if (LegacyMergeSort.userRequested)  
  3.         legacyMergeSort(a, fromIndex, toIndex);  
  4.     else  
  5.         ComparableTimSort.sort(a, fromIndex, toIndex);  
  6. }  

注意到1.7下的sort有一个分支判断,当LegacyMergeSort.userRequested为true的情况下,采用legacyMergeSort,否则采用ComparableTimSort。LegacyMergeSort.userRequested的字面意思大概就是“用户请求传统归并排序”的意思,这个分支调用的是与jdk1.5相同的方法来实现功能。

ComparableTimSort是改进后的归并排序,对归并排序在已经反向排好序的输入时表现为O(n^2)的特点做了特别优化。对已经正向排好序的输入减少回溯。对两种情况(一会升序,一会降序)的输入处理比较好(摘自百度百科)。

  • legacyMergeSort代码:
[java] view plain copy
 
 print?
  1. private static void legacyMergeSort(Object[] a,  
  2.                                     int fromIndex, int toIndex) {  
  3.     rangeCheck(a.length, fromIndex, toIndex);  
  4.     Object[] aux = copyOfRange(a, fromIndex, toIndex);  
  5.     mergeSort(aux, a, fromIndex, toIndex, -fromIndex);  
  6. }  
  • mergeSort代码:
[java] view plain copy
 
 print?
  1. private static void mergeSort(Object[] src,  
  2.                                  Object[] dest,  
  3.                                  int low,  
  4.                                  int high,  
  5.                                  int off) {  
  6.        int length = high - low;  
  7.   
  8.        // Insertion sort on smallest arrays  
  9.        if (length < INSERTIONSORT_THRESHOLD) {  
  10.            for (int i=low; i<high; i++)  
  11.                for (int j=i; j>low &&  
  12.                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)  
  13.                    swap(dest, j, j-1);  
  14.            return;  
  15.        }  
  16.   
  17.        // Recursively sort halves of dest into src  
  18.        int destLow  = low;  
  19.        int destHigh = high;  
  20.        low  += off;  
  21.        high += off;  
  22.        int mid = (low + high) >>> 1;  
  23.        mergeSort(dest, src, low, mid, -off);  
  24.        mergeSort(dest, src, mid, high, -off);  
  25.   
  26.        // If list is already sorted, just copy from src to dest.  This is an  
  27.        // optimization that results in faster sorts for nearly ordered lists.  
  28.        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {  
  29.            System.arraycopy(src, low, dest, destLow, length);  
  30.            return;  
  31.        }  
  32.   
  33.        // Merge sorted halves (now in src) into dest  
  34.        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {  
  35.            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)  
  36.                dest[i] = src[p++];  
  37.            else  
  38.                dest[i] = src[q++];  
  39.        }  
  40.    }  

①:这个方法接收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数组中。这样一次递归循环就调用完毕,如果还有循环就继续排序下去,否则排序就已经完成。

[java] view plain copy
 
 print?
  1. static void sort(Object[] a, int lo, int hi) {  
  2.         rangeCheck(a.length, lo, hi);  
  3.         int nRemaining  = hi - lo;  
  4.         if (nRemaining < 2)  
  5.             return;  // Arrays of size 0 and 1 are always sorted  
  6.   
  7.         // If array is small, do a "mini-TimSort" with no merges  
  8.         if (nRemaining < MIN_MERGE) {  
  9.             int initRunLen = countRunAndMakeAscending(a, lo, hi);  
  10.             binarySort(a, lo, hi, lo + initRunLen);  
  11.             return;  
  12.         }  
  13.   
  14.         /** 
  15.          * March over the array once, left to right, finding natural runs, 
  16.          * extending short natural runs to minRun elements, and merging runs 
  17.          * to maintain stack invariant. 
  18.          */  
  19.         ComparableTimSort ts = new ComparableTimSort(a);  
  20.         int minRun = minRunLength(nRemaining);  
  21.         do {  
  22.             // Identify next run  
  23.             int runLen = countRunAndMakeAscending(a, lo, hi);  
  24.   
  25.             // If run is short, extend to min(minRun, nRemaining)  
  26.             if (runLen < minRun) {  
  27.                 int force = nRemaining <= minRun ? nRemaining : minRun;  
  28.                 binarySort(a, lo, lo + force, lo + runLen);  
  29.                 runLen = force;  
  30.             }  
  31.   
  32.             // Push run onto pending-run stack, and maybe merge  
  33.             ts.pushRun(lo, runLen);  
  34.             ts.mergeCollapse();  
  35.   
  36.             // Advance to find next run  
  37.             lo += runLen;  
  38.             nRemaining -= runLen;  
  39.         } while (nRemaining != 0);  
  40.   
  41.         // Merge all remaining runs to complete sort  
  42.         assert lo == hi;  
  43.         ts.mergeForceCollapse();  
  44.         assert ts.stackSize == 1;  
  45.     }  

 

参考:

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

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

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

分享到:
评论

相关推荐

    jdk1.5.0_12源代码

    通过源代码,我们可以看到如何在类定义中使用`&lt;T&gt;`来创建泛型类,以及如何在方法中使用`&lt;T&gt;`来声明泛型方法。例如,`java.util.List&lt;T&gt;`接口和`Collections.sort(List)`方法展示了泛型在容器和算法上的应用。 2. **...

    559.557.JAVA基础教程_集合-Collections工具类常用方法的测试(559).rar

    Java集合框架是Java编程中不可或缺的部分,而Collections工具类则是这个框架中的一个重要工具,它提供了大量静态方法,用于操作各种集合接口(如List、Set、Queue等)的实例。本教程将深入探讨Collections工具类中的...

    java数据结构源代码

    Java中内置的`Arrays.sort()`方法可以对数组进行快速排序,而`Collections.sort()`方法则适用于列表。此外,还有一些经典的排序算法,如冒泡排序、选择排序、插入排序、快速排序、归并排序和堆排序等,它们在不同的...

    Java通讯录源代码

    【Java通讯录源代码】项目是一个使用Java编程语言在NetBeans集成开发环境中创建的实用程序,旨在模拟一个基本的联系人管理系统。这个程序的核心功能包括好友分类和排序,这些都是通过与MySQL数据库进行交互来实现的...

    Java 数据结构与算法+源代码 高清版

    同时,Java的标准库中也包含了各种排序和查找算法的实现,如Collections.sort()和Arrays.binarySearch()。 源代码部分将展示如何在Java中实现这些数据结构和算法,这对于学习和实践来说非常宝贵。通过阅读和分析...

    《零基础学算法》源代码

    同时,书中可能会包含一些常用的算法库和数据结构实现,例如Python的heapq模块、Java的Collections.sort()方法等,这些库函数可以帮助我们更高效地实现算法。 在实际操作中,读者应该动手尝试修改和优化源代码,这...

    Java学生成绩管理系统源代码

    Java学生成绩管理系统是一款基于Java语言开发的应用程序,主要用于存储、查询、修改和删除学生分数信息。...此外,源代码的注释中提及了待办事项(TODO),表明该系统可能还在开发阶段,有待完善和优化。

    jdk5.0源代码下载

    通过分析JDK 5.0的源代码,你可以学习到以下关键知识点: - **泛型**:JDK 5.0引入了泛型,允许在类型定义时指定参数化类型,提高了类型安全性和代码可读性。 - **枚举**:新增的枚举类型使得常量的表示更加规范,...

    Java的静态导入源代码

    2. 使用工具类,如`java.util.Arrays.sort()`或`java.util.Collections.reverse()`。 3. 测试框架中的断言,如JUnit的`assertThat()`。 总结来说,Java的静态导入是一种提高代码简洁度的语法特性,它允许我们直接...

    集合工具类Collections的基本应用

    集合工具类Collections是Java编程语言中的一个非常重要的辅助类,它提供了一系列静态方法,用于对各种集合框架(如List、Set、Queue等)进行操作。这些方法包括但不限于排序、查找、替换以及同步控制,极大地提高了...

    Hashmap 通过对VALUE排序 源代码

    在博文“HashMap通过对VALUE排序 源代码”中,作者可能详细介绍了如何实现上述方法,尤其是自定义Comparator来对HashMap的值进行排序。遗憾的是,由于没有提供具体的博客内容,我们无法给出更详细的源代码分析。不过...

    投票系统源代码

    在Java中,可以使用Collections.sort()方法对存储投票结果的数据结构进行排序,如果需要自定义排序规则,可以实现Comparator接口。 4. **保存投票结果**:为了保留选举数据,系统需要将投票结果持久化存储,可能是...

    jdk8源代码

    **Java Development Kit (JDK) 8 源代码详解** ...以上只是JDK 8源代码中部分关键特性的介绍。深入研究这些源代码,开发者可以更好地理解Java运行机制,提升编程技能,并且能够针对特定需求进行定制化优化。

    java编写的彩票抽奖系统源代码

    Java编写的彩票抽奖系统源代码是一个适合初学者学习和实践的项目,它提供了一个在控制台运行的友好界面,使得用户能够直观地了解彩票抽奖的基本流程。在这个项目中,我们可以学习到以下几个重要的Java编程和软件设计...

    java语言编写---通讯录源代码

    Java语言是一种广泛应用于开发各种类型软件的面向对象的编程语言,尤其在企业级应用和Web应用领域中占有重要...通过学习和分析这个源代码,开发者可以提升自己的Java编程能力,并了解如何将理论知识应用到实际项目中。

    JDK5.0新特性源代码

    在这个名为“JDK5.0新特性源代码”的压缩包中,我们可以期待找到与这些关键特性相关的源代码示例。以下是JDK 5.0引入的一些核心新特性及其详细解释: 1. **泛型(Generics)**:泛型允许在类、接口和方法中声明类型...

    插入排序c#源代码

    根据给定的文件信息,我们可以总结出以下关于“插入排序C#源代码”的相关知识点: ### 插入排序算法概述 插入排序(Insertion Sort)是一种简单直观的比较排序算法。它的工作原理是通过构建有序序列,对于未排序...

    Android安卓源码-字母排序类源代码(3例).zip

    - 使用Collections.sort():Android提供了内置的排序方法,适用于ArrayList和数组,可以直接对字符序列进行排序,简化代码。 - 算法选择:根据数据规模和特性选择合适的排序算法,例如,快速排序通常比冒泡排序更...

    DSA.rar_CSharp 数据结构_DSA CSharp_DSA 源代码_DSA算法_dsa

    1. 排序算法:如冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序等,C#中可以自定义实现,也可以用`Array.Sort()`或`List&lt;T&gt;.Sort()`方法。 2. 搜索算法:线性搜索、二分搜索、哈希搜索等,用于在数据...

    MongoDB Java操作大全 源代码 实例

    MongoDB是一种流行的、高性能的NoSQL数据库,特别适合处理大量非...本资源包中的源代码实例将涵盖以上所有操作,通过实际运行这些示例,开发者可以更好地理解MongoDB的Java操作,从而在项目中更加熟练地运用MongoDB。

Global site tag (gtag.js) - Google Analytics