Java中Arrays、Collections的Sort方法

Collections类提供了两个sort方法,目标都是List<T> list,不同时可选择自己指定一个Comparator。

public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}
public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

调用的都是list的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);
        }
    }

调用的是Arrays的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);
        }
    }

期三行调用的sort:

 

public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
    }

具体的排序细节就不展示了,最后两个片段可以看出。Array提供了两种排序算法,MergeSort和TimSort。默认用的是Java7新提供的TimSort,通过在启动参数中指定-Djava.util.Arrays.useLegacyMergeSort=true可以用原来的MergeSort。这里的TimSort不少人被一个细节坑过,异常如下:

Exception in thread "main" java.lang.IllegalArgumentException: Comparison
method violates its general contract!

 

原因是,使用TimSort时,对象间的对比较更加严格,当指定compare时,必须保证以下三点:

a). sgn(compare(x, y)) == -sgn(compare(y, x))
b). (compare(x, y)>0) && (compare(y, z)>0) 意味着 compare(x, z)>0
c). compare(x, y)==0 意味着对于任意的z:sgn(compare(x, z))==sgn(compare(y, z)) 均成立
后两点很容易满足,大多数问题都出在第一点上,例如我曾经的这个实现:
public int compare(Test o1, Test o2) {
    return o1.getValue() > o2.getValue() ? 1 : -1;
}

乍一看没什么毛病,但是对比上面的条件a,就会发现不满足了,那就是:当o1的value与o2的value相等时!

解决方法:

 

public int compare(Test o1, Test o2) {
    return o1.getValue() == o2.getValue() ? 0 : (o1.getValue() > o2.getValue() ? 1 : -1);
}

 

有空会补上MergeSort和TimSort的介绍。

 

你可能感兴趣的:(Java中Arrays、Collections的Sort方法)