我正在使用JDK-8(x64)。对于Arrays.sort
(原语),我在Java文档中找到了以下内容:
排序算法是Vladimir Yaroslavskiy,Jon Bentley和Joshua Bloch的Dual-Pivot Quicksort 。
对于Collections.sort
(对象),我发现了这个“Timsort”:
此实现是一个稳定的,自适应的,迭代的 mergesort ...此实现将指定的列表转储到数组中,对数组进行排序,并迭代列表重置来自数组中相应位置的每个元素。
如果Collections.sort
使用数组,为什么不调用Arrays.sort
或使用双轴 QuickSort ?为什么要使用 Mergesort ?
答案 0 :(得分:82)
API保证了Quicksort不提供的稳定排序。但是,当按照自然顺序对原始值进行排序时,您不会注意到差异,因为原始值没有标识。因此,Quicksort用于原始数组,因为它的效率稍高。
对于您可能会注意到的对象,当根据equals
实现或提供的Comparator
认为相同的对象更改其顺序时。因此,Quicksort不是一个选择。因此使用MergeSort的变体,当前的Java版本使用 TimSort 。这同样适用于Arrays.sort
和Collections.sort
,但使用Java 8时,List
本身可能会覆盖排序算法。
答案 1 :(得分:18)
我不知道文档,但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
(对象元素)。此实现使用合并排序或时间排序。
答案 2 :(得分:15)
根据Javadoc,只使用Quicksort对原始数组进行排序。对象数组也使用Mergesort进行排序。
所以Collections.sort似乎使用与Arrays.sort for Objects相同的排序算法。
另一个问题是为什么原始数组使用不同的排序算法而不是Object数组?
答案 3 :(得分:2)
正如许多答案所述。
Quicksort被Arrays.sort用于对原始集合进行排序,因为不需要稳定性(您不知道或不关心在排序中是否交换了两个相同的整数)
MergesSort或更具体地说,Arrays.sort使用Timsort来排序对象集合。需要稳定性。 Timsort确实没有提供稳定性。
Collections.sort委托给Arrays.sort,这就是你看到引用MergeSort的javadoc的原因。
答案 4 :(得分:1)
快速排序在合并排序时有两个主要缺点:
稳定性对于原始类型来说不是问题,因为没有不同于(值)相等的身份概念。
在对任意对象进行排序时,稳定性是一个大问题。无论输入是什么,Merge Sort都能保证n log n(时间)性能,这是一个很好的附带好处。 这就是选择合并排序以提供稳定排序(合并排序)以对对象引用进行排序的原因。