JAVA Comparator 自定義排序 原始碼分析

Shie1d發表於2024-05-13

對於一個陣列來說
如果我們想要從大到小排序一般會這麼寫

Integer[] nums = {1,2,3};
Arrays.sort(nums, new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return b - a;
            }
        });
//lambda 表示式
Arrays.sort(nums, (a, b) -> b - a);

為什麼這麼寫可以? 我們以 Arrays.sort 原始碼為例看看到底是怎麼排序的。

private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low, int high, int off,
                                  Comparator c) {// c 就是我們實現的Comparator
        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++];
        }
    }

可以看到底層用的是歸併排序,我們直接看最下面幾行程式碼。

// 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++];
}

判斷兩數大小呼叫了我們實現的 Comparator c.compare

Arrays.sort(nums, (a, b) -> b - a);

那麼分為兩種情況

1.src[p] >= src[q]
那麼 c.compare(src[p], src[q]) 我們返回的是 src[q] - src[p] 返回的是一個小於等於0的數 也就意味著 下標 p++ 也就是說誰大誰的下標後移了
也就實現了從大到小排序

2.src[p] < src[q]
同上分析

對於其他的資料結構排序也是同樣的規則

相關文章