为什么Collections.sort使用Mergesort但Arrays.sort不?
我正在使用JDK-8(x64)。 对于Arrays.sort
我在Java文档中find了以下内容:
sortingalgorithm是由Vladimir Yaroslavskiy,Jon Bentley和Joshua Bloch提供的Dual-Pivot Quicksort 。
对于Collections.sort
我发现这个:
这个实现是一个稳定的,自适应的,迭代的mergesort …这个实现把指定的列表转储到一个数组中,对数组进行sorting ,然后对列表进行迭代,以重置数组中相应位置的每个元素。
如果Collections.sort
使用数组,为什么不调用Arrays.sort
或使用双枢轴QuickSort ? 为什么使用Mergesort ?
API保证Quicksort不提供稳定的sorting。 但是,当按照自然顺序对原始值进行sorting时,由于原始值没有标识,因此不会注意到差异。 因此,Quicksort用于原始数组,因为它稍微有效一些。
对于您可能会注意到的对象,根据等式实现或提供的Comparator
器视为相同的对象更改其顺序时。 因此,Quicksort不是一个选项。 所以使用MergeSort的一个变体,当前的Java版本使用TimSort 。 这适用于Arrays.sort
和Collections.sort
,但对于Java 8, List
本身可能会覆盖sortingalgorithm。
我不知道文档,但Java 8(HotSpot)中的java.util.Collections#sort
的实现如下所示:
@SuppressWarnings({"unchecked", "rawtypes"}) public static <T> void sort(List<T> list, Comparator<? super T> c) { list.sort(c); }
而List#sort
有这个实现:
@SuppressWarnings({"unchecked", "rawtypes"}) 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); } }
所以最后, Collections#sort
在后台使用Arrays#sort
(对象元素)。 此实现使用合并sorting或timsorting。
根据Javadoc,只有原始数组使用Quicksortsorting。 对象数组也使用Mergesort进行sorting。
所以Collections.sort似乎使用与Arrays.sort对象相同的sortingalgorithm。
另一个问题是为什么一个不同的sortingalgorithm用于原始数组而不是对象数组?
正如许多答案中所述。
Arrays.sort使用Quicksort来对原始集合进行sorting,因为不需要稳定性(您不会知道或关心两个相同的整数是否在sorting中交换)
MergeSort或更具体地说,Timsort被Arrays.sort用来sorting对象的集合。 稳定性是必需的。 Timsort确实没有提供Quicksort的稳定性。
Collections.sort委托给Arrays.sort,这就是您看到引用MergeSort的javadoc的原因。
对于合并sorting,Quick Sort有两个主要缺点:
- 它不是非稳定的,而是非原始的。
- 它不保证n日志性能。
对于原始types来说,稳定性不是问题,因为没有认同(value)相等的概念。
sorting任意对象时,稳定性是一件大事。 无论input什么,合并sorting都能保证n日志(时间)性能,这是一个很好的优势。 这就是为什么select合并sorting来提供稳定的sorting(合并sorting)来sorting对象引用。