Collections.sort

事实上Collections.sort方法底层就是调用的Arrays.sort方法,而Arrays.sort使用了两种排序方法,快速排序和优化的归并排序。

快速排序主要是对那些基本类型数据(int,short,long等)排序, 而归并排序用于对Object类型进行排序。

使用不同类型的排序算法主要是由于快速排序是不稳定的,而归并排序是稳定的。这里的稳定是指比较相等的数据在排序之后仍然按照排序之前的前后顺序排列。对于基本数据类型,稳定性没有意义,而对于Object类型,稳定性是比较重要的,因为对象相等的判断可能只是判断关键属性,最好保持相等对象的非关键属性的顺序与排序前一致;另外一个原因是由于归并排序相对而言比较次数比快速排序少,移动(对象引用的移动)次数比快速排序多,而对于对象来说,比较一般比移动耗时。

public static <T extends Comparable<? super T>> void sort(List<T> list) {list.sort(null);
}

List#sort

default void sort(Comparator<? super E> c) {Object[] a = this.toArray();Arrays.sort(a, (Comparator) c);ListIterator<E> i = this.listIterator();for (Object e : a) {i.next();i.set((E) e);}
}public static <T> void sort(T[] a, Comparator<? super T> c) {if (c == null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);}
}public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

TimSort

结合了归并排序和插入排序的混合算法,它基于一个简单的事实,实际中大部分数据都是部分有序(升序或降序)的。

TimSort 算法为了减少对升序部分的回溯和对降序部分的性能倒退,将输入按其升序和降序特点进行了分区。排序的输入的单位不是一个个单独的数字,而是一个个的块-分区。其中每一个分区叫一个run。针对这些 run 序列,每次拿一个 run 出来按规则进行合并。每次合并会将两个 run合并成一个 run。合并的结果保存到栈中。合并直到消耗掉所有的 run,这时将栈上剩余的 run合并到只剩一个 run 为止。这时这个仅剩的 run 便是排好序的结果。

综上述过程,Timsort算法的过程包括

(0)如果数组长度小于某个值,直接用二分插入排序算法

(1)找到各个run,并入栈

(2)按规则合并run


/*** Sorts the given range, using the given workspace array slice* for temp storage when possible. This method is designed to be* invoked from public methods (in class Arrays) after performing* any necessary array bounds checks and expanding parameters into* the required forms.** @param a the array to be sorted* @param lo the index of the first element, inclusive, to be sorted* @param hi the index of the last element, exclusive, to be sorted* @param work a workspace array (slice)* @param workBase origin of usable space in work array* @param workLen usable size of work array* @since 1.8*/
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {assert a != null && lo >= 0 && lo <= hi && hi <= a.length;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 mergesif (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, work, workBase, workLen);int minRun = minRunLength(nRemaining);do {// Identify next runint 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 mergets.pushRun(lo, runLen);ts.mergeCollapse();// Advance to find next runlo += runLen;nRemaining -= runLen;} while (nRemaining != 0);// Merge all remaining runs to complete sortassert lo == hi;ts.mergeForceCollapse();assert ts.stackSize == 1;
}
/*** Creates a TimSort instance to maintain the state of an ongoing sort.** @param a the array to be sorted* @param work a workspace array (slice)* @param workBase origin of usable space in work array* @param workLen usable size of work array*/
private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) {this.a = a;// Allocate temp storage (which may be increased later if necessary)int len = a.length;int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;if (work == null || workLen < tlen || workBase + tlen > work.length) {tmp = new Object[tlen];tmpBase = 0;tmpLen = tlen;}else {tmp = work;tmpBase = workBase;tmpLen = workLen;}/** Allocate runs-to-be-merged stack (which cannot be expanded).  The* stack length requirements are described in listsort.txt.  The C* version always uses the same stack length (85), but this was* measured to be too expensive when sorting "mid-sized" arrays (e.g.,* 100 elements) in Java.  Therefore, we use smaller (but sufficiently* large) stack lengths for smaller arrays.  The "magic numbers" in the* computation below must be changed if MIN_MERGE is decreased.  See* the MIN_MERGE declaration above for more information.* The maximum value of 49 allows for an array up to length* Integer.MAX_VALUE-4, if array is filled by the worst case stack size* increasing scenario. More explanations are given in section 4 of:* http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf*/int stackLen = (len <    120  ?  5 :len <   1542  ? 10 :len < 119151  ? 24 : 49);runBase = new int[stackLen];runLen = new int[stackLen];
}

MergeSort

private static void legacyMergeSort(Object[] a) {Object[] aux = a.clone();mergeSort(aux, a, 0, a.length, 0);
}private static void mergeSort(Object[] src,Object[] dest,int low,int high,int off) {int length = high - low;// 7// Insertion sort on smallest arraysif (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 srcint 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 destfor(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++];elsedest[i] = src[q++];}
}

总结

小于60:使用插入排序,插入排序是稳定的
    大于60的数据量会根据数据类型选择排序方式:
         基本类型:使用快速排序。因为基本类型。1、2都是指向同一个常量池不需要考虑稳定性。
         Object类型:使用归并排序。因为归并排序具有稳定性。
    注意:不管是快速排序还是归并排序。在二分的时候小于60的数据量依旧会使用插入排序

终于,我读懂了所有Java集合——sort相关推荐

  1. 终于,我读懂了所有Java集合——map篇

    首先,红黑树细节暂时撸不出来,所以没写,承诺年前一定写 HashMap (底层是数组+链表/红黑树,无序键值对集合,非线程安全) 基于哈希表实现,链地址法. loadFactor默认为0.75,thr ...

  2. 终于,我读懂了所有Java集合——map篇(多线程)

    多线程环境下的问题 1.8中hashmap的确不会因为多线程put导致死循环(1.7代码中会这样子),但是依然有其他的弊端,比如数据丢失等等.因此多线程情况下还是建议使用ConcurrentHashM ...

  3. 终于,我读懂了所有Java集合——List篇

    ArrayList 基于数组实现,无容量的限制. 在执行插入元素时可能要扩容,在删除元素时并不会减小数组的容量,在查找元素时要遍历数组,对于非null的元素采取equals的方式寻找. 是非线程安全的 ...

  4. 终于,我读懂了所有Java集合——queue篇

    Stack 基于Vector实现,支持LIFO. 类声明 public class Stack<E> extends Vector<E> {} push public E pu ...

  5. 终于,我读懂了所有Java集合——set篇

    HashSet (底层是HashMap) Set不允许元素重复. 基于HashMap实现,无容量限制. 是非线程安全的. 成员变量 private transient HashMap<E,Obj ...

  6. 图解易经:一部终于可以读懂的易经 祖行 扫描版 陕西师范大学出版社

    图解易经:一部终于可以读懂的易经  祖行  扫描版  陕西师范大学出版社

  7. 《图解易经:一本终于可以读懂的易…

    <图解易经:一本终于可以读懂的易经>(祖行)扫描版[PDF] 中文名: 图解易经:一本终于可以读懂的易经 作者: 祖行 图书分类: 教育/科技 资源格式: PDF 版本: 扫描版 出版社: ...

  8. Java集合sort()

    Today we will look into Java Collections sort method. While working with Collections in java, more t ...

  9. 一文读懂什么是Java中的自动拆装箱

    本文主要介绍Java中的自动拆箱与自动装箱的有关知识. 基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型.它们是我们编程中使用最频繁的类型. Java是一种强类型 ...

最新文章

  1. websocket采用tomcat方式,IOC类对象无法注入的解决方案
  2. java设计模式 单例_java设计模式一(单例模式singleton)
  3. 【ubuntu-version】 几种常见工具查看版本的命令
  4. 高铁上的排泄物都哪里去了,真的是“一泻千里”吗?
  5. InceptionNet V4
  6. 如何将DB2数据库转换成Oracle数据库,这一篇告诉你
  7. winfrom 如何让弹窗不影响主界面_「Win」电脑开机后不给我弹几个广告,我还不太习惯...
  8. hexo需要先编辑好html文件吗,教你定制Hexo的landscape打造自己的主题_html/css_WEB-ITnose...
  9. struts2 国际化 cookie保存语言, 下次访问时显示当前设置的语言
  10. a标签创建超链接,利用a标签创建锚点
  11. 使用ffmpeg推流拉流
  12. Cron在线表达式生成器
  13. 自考本科计算机要学什么,计算机自考本科需要考哪些科目
  14. 递归回溯求解数独 C++实现方法
  15. 解决Oracle进入实例账号,练习表的问题
  16. 动态规划 -- 钢条切割问题
  17. 2016 Youtube 推荐系统介绍
  18. 刚体质量分布与牛顿-欧拉方程
  19. python怎么在图片上写字_python在图片上写汉字
  20. 浪潮之巅第十三章 — 高科技公司的摇篮:斯坦福大学

热门文章

  1. java arraycopyof_Java中System.arraycopy()和Arrays.copyOf()的区别
  2. java gc回收算法_Java GC回收算法-判定一个对象是否可以回收
  3. 现实地形导入UE4全流程
  4. asterisk for mipsel
  5. 领导者/追随者(Leader/Followers)模型和半同步/半异步(half-sync/half-async)模型
  6. 设计模式C++实现 ——状态模式
  7. 硬件服务器采购指南,硬件组装_服务器采购指南_太平洋电脑网PConline
  8. 32命令模式(Command Pattern)
  9. linq、lambda、entity framework之间的关系
  10. 由浅到深理解ROS(1)