Collections.sort() in JDK1.6

本文主要介紹了Collections.sort方法在JDK1.6中的源碼實現(JDK版本1.6.0_45)html

1.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]);
        }
    }

首先這個方法將list轉換爲數組並調用了Arrays.sort()方法(至於這個Comparator是一種比較器,外界須要實現其compare方法;還有一種是Comparable,實現的是compareTo方法,有興趣的能夠研究一下。),在對數組進行排序以後,經過迭代器將排序結果更新到list中。(迭代器的相關知識不作介紹了,由於我也沒看這部分的源碼)數組

2.Arrays.sort()源碼分析

public static <T> void sort(T[] a, Comparator<? super T> c) {
    T[] aux = (T[])a.clone();
        if (c==null)
            mergeSort(aux, a, 0, a.length, 0);
        else
            mergeSort(aux, a, 0, a.length, 0, c);
    }

先是利用Object的clone方法建立了一個a的副本對象(Object的clone方法爲淺克隆方式,它只克隆了自身對象和對象內部實例變量的地址引用。也就是說在堆內存只是建立了a自身副本對象,而在棧內存中建立了對象內部實例變量的地址引用副本。)spa

判斷比較器c存不存在,實際上mergeSort(aux, a, 0, a.length, 0)和mergeSort(aux, a, 0, a.length, 0, c)內部實現方式同樣,只是若是比較器c(Comparator)不存在,mergeSort(aux, a, 0, a.length, 0)內部會使用Comparable比較器的compareTo方法。.net

3.mergeSort(歸併排序)指針

private static void mergeSort(Object[] src, Object[] dest, int low,
            int high, int off, Comparator c) {
        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 && c.compare(dest[j - 1], 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, c);
        mergeSort(dest, src, mid, high, -off, c);

        // 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 (c.compare(src[mid - 1], 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 && c.compare(src[p], src[q]) <= 0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }

這一部分代碼比較多,首先程序會經過判斷length < INSERTIONSORT_THRESHOLD(INSERTIONSORT_THRESHOLD默認爲7),若是數組長度小於7,會使用直接插入排序算法。code

這個上張圖解釋一下,圖片來源http://www.javashuo.com/article/p-mnytybcp-hm.htmlhtm

如今來看一下代碼,代碼很簡單,兩個循環,外層循環遍歷數組(圖中的待排序序列),內層循環將每一次待排序的值按順序放入有序序列中(只是一種表達方式,實際上就是交換),好比圖中在對1進行插入時,會先跟前一個元素9進行比較,1<9,交換位置,而後1再跟前一個元素3比較,1<3,交換位置。對象

要是數組長度不小於7呢,就會使用歸併排序算法啦,有關歸併排序算法的介紹能夠參考這篇博客http://www.javashuo.com/article/p-nkdsmljg-cd.html,這裏就不貼圖了。

歸併排序的核心思想呢就是分而治之嘛,提及來挺容易的哈!

下面代碼經過採用遞歸方式實現分的思想,分到最後仍是用了直接插入排序,這個有個地方須要注意一下,就是src和dest的參數位置(數組的起止位置就不用說了吧!),在調用遞歸時,是將src數組做爲排序對象進行排序的,而後dest數組是依據src進行排序(下邊代碼具體說)。

int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off, c);
mergeSort(dest, src, mid, high, -off, c);

如今分完了,怎麼治呢?前面所說的dest數組是依據src進行排序在此進行了體現,最開始說的兩個mergeSort方法的不一樣之處(比較器)在這也能看出。

首先有一種特別友好的狀況,那就是分完的前半部分最大的那個正好小於等於後半部分最小的元素(這只是遞歸過程當中的一個分支),那麼皆大歡喜,src數組已是有序的了,只需將src數組複製到目標數組中(System.arraycopy具體用法自行上網查吧)。

// 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 (c.compare(src[mid - 1], 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 && c.compare(src[p], src[q]) <= 0)
           dest[i] = src[p++];
     else
           dest[i] = src[q++];
}

其餘狀況怎麼處理呢,這個再貼張圖,圖片來源https://blog.csdn.net/ghsau/article/details/42060651,這篇博客是我參考的博客,你們也能夠看看。

思想很簡單,循環整個數組,比較左邊的元素和右邊的元素,誰小把誰放到dest中(再次重申,這只是遞歸過程當中的一個分支),而後移動對應指針,直到src全部元素都放入到dest中。

例如一開始是2和1進行比較,1小放入dest中,p不變,q指向5(看作指針),i指向下一個位置;2和5比較,2小放入dest中,p指向3,q不變,i指向下一個位置,以此類推,直到循環結束。

到這裏算是寫完了,寫的可能很差,剛畢業大學生水平有限,工做以後的第一篇博客,請原諒我一些地方的無知;若是有什麼錯誤,請必定要指出,萬分感謝,您的意見是我成長的催化劑。

下面整理一下參考資料。

https://blog.csdn.net/ghsau/article/details/42060651

https://www.jianshu.com/p/1efc3aa1507b

http://www.javashuo.com/article/p-mnytybcp-hm.html

http://www.javashuo.com/article/p-nkdsmljg-cd.html

 後面若是有機會,會寫一篇jdk1.7以後有關sort這一部分的博客。

疑問:mergeSort中有一個off參數,我的理解是限制排序集合的區域範圍(起止怎麼肯定的。。。)?JDK1.7中sort方法中的paramInt1和paramInt2是否是起到了相似的功能?

相關文章
相關標籤/搜索