源码阅读--Collections.sort
2017-02-19 19:50
169 查看
Collections.sort源代码
跟踪Arrays.sort
LegacyMergeSort.userRequested指的啥呢?
这是一个boolean值。说白了就是,如果用户指定归并排序那就归并排序,否则就是ComparableTimSort。归并排序比较常见,就不讲了。贴一下ComparableTimSort
算法思想如下:
1.构造minRun,值等于长度的一直除以2,直到小于MIN_MERGE
2.(这一步会无限循环)
(1)寻找第一个拐点,记为index。如果index小于minRun,那就对整个minRun数据二分排序。
(2)将起始位置和拐点位置push进去,然后对当前的各区块进行merge。
由于要合并的两个 run 是已经排序的,所以合并的时候,有会特别的技巧。
假设两个 run 是 run1,run2 ,先用 gallopRight在 run1里使用 binarySearch 查找run2 首元素 的位置k, 那么 run1 中 k 前面的元素就是合并后最小的那些元素。然后,在run2 中查找run1 尾元素 的位置 len2 ,那么run2 中 len2 后面的那些元素就是合并后最大的那些元素。最后,根据len1 与len2 大小,调用mergeLo或者 mergeHi 将剩余元素合并。
public static <T extends Comparable<? super T>> void sort(List<T> list) { Object[] a = list.toArray(); Arrays.sort(a);// ListIterator<T> i = list.listIterator(); for (int j=0; j<a.length; j++) { i.next(); i.set((T)a[j]); } }
跟踪Arrays.sort
public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a); else ComparableTimSort.sort(a); }
LegacyMergeSort.userRequested指的啥呢?
static final class LegacyMergeSort { private static final boolean userRequested = java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction( "java.util.Arrays.useLegacyMergeSort")).booleanValue(); }
这是一个boolean值。说白了就是,如果用户指定归并排序那就归并排序,否则就是ComparableTimSort。归并排序比较常见,就不讲了。贴一下ComparableTimSort
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) {//***********************************如果长度小于MIN_MERGE(32),那就用二分排序算法 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) { //如果拐点小于minRun,就对整个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);//**********************这里的runLen>=minRun ts.mergeCollapse();//*************调用mergeAt // Advance to find next run lo += runLen; nRemaining -= runLen; } while (nRemaining != 0); // Merge all remaining runs to complete sort assert lo == hi; ts.mergeForceCollapse();//*************也会调用mergeAt assert ts.stackSize == 1; } //minRunLength------一直取二分之一,直到小于MIN_MERGE(32) // n=奇数,return (n-1)/2+1。n=偶数,return n/2 private static int minRunLength(int n) { assert n >= 0; int r = 0; // Becomes 1 if any 1 bits are shifted off while (n >= MIN_MERGE) { r |= (n & 1); n >>= 1; } return n + r; } //countRunAndMakeAscending // 全是升序,那就返回high // 全是降序,那就返回high,并且要翻转 // 先升后降,返回最高点 // 先降后升,返回最低点,并且之前的翻转 // 说白了就是返回拐点 private static int countRunAndMakeAscending(Object[] a, int lo, int hi) { assert lo < hi; int runHi = lo + 1; if (runHi == hi) return 1; // Find end of run, and reverse range if descending if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0) runHi++; reverseRange(a, lo, runHi); } else { // Ascending while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0) runHi++; } return runHi - lo; } // ********************理解gallopRight和gallopLeft private void mergeAt(int i) { int base1 = runBase[i]; int len1 = runLen[i]; int base2 = runBase[i + 1]; int len2 = runLen[i + 1]; /* * Record the length of the combined runs; if i is the 3rd-last * run now, also slide over the last run (which isn't involved * in this merge). The current run (i+1) goes away in any case. */ runLen[i] = len1 + len2; if (i == stackSize - 3) { runBase[i + 1] = runBase[i + 2]; runLen[i + 1] = runLen[i + 2]; } stackSize--; /* * Find where the first element of run2 goes in run1. Prior elements * in run1 can be ignored (because they're already in place). */ int k = gallopRight((Comparable<Object>) a[base2], a, base1, len1, 0); assert k >= 0; base1 += k; len1 -= k; if (len1 == 0) return; /* * Find where the last element of run1 goes in run2. Subsequent elements * in run2 can be ignored (because they're already in place). */ len2 = gallopLeft((Comparable<Object>) a[base1 + len1 - 1], a, base2, len2, len2 - 1); assert len2 >= 0; if (len2 == 0) return; // Merge remaining runs, using tmp array with min(len1, len2) elements if (len1 <= len2) mergeLo(base1, len1, base2, len2); else mergeHi(base1, len1, base2, len2); }
算法思想如下:
1.构造minRun,值等于长度的一直除以2,直到小于MIN_MERGE
2.(这一步会无限循环)
(1)寻找第一个拐点,记为index。如果index小于minRun,那就对整个minRun数据二分排序。
(2)将起始位置和拐点位置push进去,然后对当前的各区块进行merge。
由于要合并的两个 run 是已经排序的,所以合并的时候,有会特别的技巧。
假设两个 run 是 run1,run2 ,先用 gallopRight在 run1里使用 binarySearch 查找run2 首元素 的位置k, 那么 run1 中 k 前面的元素就是合并后最小的那些元素。然后,在run2 中查找run1 尾元素 的位置 len2 ,那么run2 中 len2 后面的那些元素就是合并后最大的那些元素。最后,根据len1 与len2 大小,调用mergeLo或者 mergeHi 将剩余元素合并。
相关文章推荐
- 【内省式排序】能不能让sort排序在某种情况下更快呢?阅读sort源码后有感...
- Collections.sort() 排序算法 源码简介
- TiDB 源码阅读系列文章(十五)Sort Merge Join
- Collections.shuffle源码阅读
- 深入jdk——追踪Collections.sort 引发的bug(3)TimSort源码解读
- 源码阅读笔记 - 1 MSVC2015中的std::sort
- 集合类Collections.sort()的源码分析
- java 集合中的Collections.sort()排序方法的源码分析(一)
- Java Collections Framework之Arrays(method:sort(),binarySearch(),copyOf())部分源码分析(基于JDK1.6)
- Collections源码阅读与理解
- Collections.sort源码分析
- java源码阅读笔记(1)- Object
- Redis源码阅读之ae.c
- jquery源码阅读知识储备(3)exec() 方法和match方法
- 【vc】【STL源码】vector,deque与sort的用法比较及入门
- android 源码阅读之-----ADN实现
- avalon源码阅读(1)
- Linux源码阅读:以后怎么看源码的思考
- 《java.util.concurrent 包源码阅读》 结束语