Java 6的Arrays.sort
方法使用Quicksort作为基元数组,并对对象数组进行合并排序。我相信大多数时候Quicksort比合并排序更快,并且内存更少。我的实验支持这一点,尽管两种算法都是O(n log(n))。那么为什么不同的算法用于不同的类型?
答案 0 :(得分:171)
最可能的原因:快速排序不是稳定,即相等的条目可以在排序期间改变其相对位置;除此之外,这意味着如果您对已排序的数组进行排序,它可能不会保持不变。
由于原始类型没有标识(没有办法区分具有相同值的两个整数),这对它们无关紧要。但对于参考类型,它可能会导致某些应用程序出现问题。因此,使用稳定的合并排序。
OTOH,不对原始类型使用(保证n * log(n))稳定合并排序的原因可能是它需要复制数组。对于引用类型,引用对象通常占用的内存比引用数组多得多,这通常无关紧要。但对于原始类型,克隆数组会使内存使用量翻倍。答案 1 :(得分:22)
根据this answer中引用的Java 7 API文档,对象数组的Arrays#Sort()
现在使用TimSort,它是MergeSort和InsertionSort的混合体。另一方面,原始数组的Arrays#sort()
现在使用Dual-Pivot QuickSort。这些更改是从Java SE 7开始实现的。
答案 2 :(得分:12)
我能想到的一个原因是,快速排序的最坏情况时间复杂度为O( n ^ 2 ),而mergesort保留了O的最差情况时间( n log n )。对于对象数组,有一个公平的期望是会有多个重复的对象引用,这是quicksort最差的一种情况。
有一个不错的visual comparison of various algorithms,请特别注意不同算法的最右边的图表。
答案 3 :(得分:4)
我正在参加关于算法的Coursera课程,并在其中一个讲座中提到Bob Sedgewick教授提到Java系统评估的评估:
“如果程序员正在使用对象,那么空间可能不是批判性的 重要的考虑因素和合并排序使用的额外空间可能 不是问题。如果程序员使用原始类型,也许 性能是最重要的,所以他们使用快速排序。“
答案 4 :(得分:0)
Java的.find()
方法使用快速排序,插入排序和合并排序。在OpenJDK代码中甚至实现了单个和双枢轴快速排序。最快的排序算法取决于具体情况,获胜者是:小数组的插入排序(当前选择47个),大多数排序数组的mergesort,以及其余数组的快速排序,因此Java的Array.sort()尝试选择基于这些标准应用的最佳算法。
答案 5 :(得分:0)
java.util.Arrays 将 quicksort 用于基本类型,例如int,将 mergesort 用于实现 Comparable 的对象>或使用比较器。使用两种不同方法的想法是,如果程序员使用对象的空间可能不是至关重要的考虑因素,那么 mergesort 所使用的额外空间可能不是问题,并且程序员使用的原始类型可能是性能是最重要的事情,因此请使用快速排序。
例如: 这是排序稳定性很重要的示例。
这就是为什么稳定排序对对象类型有意义,尤其是可变对象类型和具有比排序键更多数据的对象类型的原因,而mergesort就是这种排序。但是对于原始类型,稳定性不仅无关紧要。没有意义。
来源:INFO