源碼剖析(二) Collections.sort 集合排序(List)

Collections.sort 這個方法使用了很多次了,剖析他的源碼的意義很重要

1.實體類 (爲了節省篇幅,大幅度削減)

public class Product {  
    private int productId;
}

2.排序使用 (下方爲正序排序,逆序只需要return o2.getProductId() - o1.getProductId();)

Collections.sort(productList, new Comparator<Product>() {
            @Override
            public int compare(Product o1, Product o2) {
                return o1.getProductId() - o2.getProductId();
            }
});

3.sort方法源碼

//第一步 調用list的sort方法
public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}

//第二步 調用Arrays.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);
        }
}

//第三步 傳入比較器Comparator 調用TimSort.sort 方法
public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            //此排序將在未來版本刪除
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
}

4.TimSort.sort (排序所使用的算法)

TimSort 是一個歸併排序做了大量優化的版本。對歸併排序排在已經反向排好序的輸入時做了特別優化。對已經正向排好序的輸入減少回溯。對兩種情況混合(一會升序,一會降序)的輸入處理比較好。(來自百度百科)

查看源碼發現,Timsort是結合了合併排序(merge sort)和插入排序(insertion sort)而得出的排序算法,它在使用中有很好的效率。

static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
        assert c != null && 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 merges
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            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.
         */
        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi, c);

            // 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, c);
                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;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章