JAVA Comparator 自定义排序 源码分析

自定义排序我们需要实现 Comparator compare 方法
函数式接口可以使用 Lambda 表达式来创建实例

@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);
}

对于一个数组来说
如果我们想要从大到小排序一般会这么写

Integer[] nums = {1,2,3}; // 注意是Integer 包装类型
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]
同上分析

对于其他的数据结构排序也是同样的规则

posted @ 2024-05-13 14:25  Shie1d  阅读(134)  评论(0)    收藏  举报