为什么Java的Arrays.sort方法对不同类型使用两种不同的排序算法?


121

Java 6的Arrays.sort方法对基元数组使用Quicksort,对对象数组使用合并sort。我相信大多数时候,Quicksort比合并排序要快,并且占用的内存更少。我的实验支持这一点,尽管两种算法都是O(n log(n))。那么为什么对不同类型使用不同的算法呢?


14
Quicksort最坏的情况是N ^ 2而不是NlogN。
codaddict

等一下,如果您有Integers 数组或其他东西,会发生什么?
Tikhon Jelvis 2010年

1
您阅读的原文没有解释吗?
汉弗莱·鲍嘉

5
该信息不再是当前的。从Java SE 7开始,MergeSort已被TimSort取代,而QuickSort已被Dual-Pivot QuickSort取代。请参阅下面的答案,以获取指向Java API文档的链接。
威尔·伯恩

Answers:


200

最可能的原因是:快速排序不稳定,即相等的条目可以在排序过程中更改其相对位置;除其他外,这意味着,如果对已排序的数组进行排序,则它可能不会保持不变。

由于基本类型没有身份(无法区分具有相同值的两个int),因此这对它们无关紧要。但是对于引用类型,它可能会在某些应用程序中引起问题。因此,对于那些使用稳定的合并排序。

OTOH,不对原始类型使用(保证的n * log(n))稳定合并排序的一个原因可能是它需要克隆该数组。对于引用类型,引用的对象通常比引用数组占用更多的内存,这通常没有关系。但是对于原始类型,完全克隆数组会使内存使用量增加一倍。


1
使用快速排序的另一个原因是,在一般情况下,快速排序比合并排序要快。尽管quicksort的功能比mergesort的功能更多,但数组访问的功能却少得多。如果输入包含大量重复的条目,则三向快速排序也可以实现线性时间,这在实际应用中并不罕见(我猜是双枢轴快速排序也具有此属性)。
蒋经国姚明

对于原始类型,它不会克隆数组,而是可以对它们进行排序,因此,我认为唯一的原因是稳定性契约,基本上是……
rogerdpack


12

我能想到的一个原因是,快速排序的最坏情况时间复杂度为O(n ^ 2),而归并排序保留的最坏情况时间为O(n log n)。对于对象数组,有一个公平的期望,即会有多个重复的对象引用,这是quicksort最差的一种情况。

各种算法都有不错的视觉比较,请特别注意不同算法的最右图。


2
Java快速排序是一种经过修改的快速排序,它不影响O(n ^ 2),来自docs“此算法在许多数据集上提供n * log(n)性能,导致其他快速排序降级为二次性能”
sbridges

7

我正在上Coursera算法课程,并在Bob Bo Bedgewick教授的讲座之一中提到对Java系统排序的评估:

“如果程序员使用对象,那么空间可能不是至关重要的考虑因素,合并排序所使用的额外空间可能不是问题。而且,如果程序员使用的是原始类型,那么性能是最重要的,因此他们使用快速排序。”


4
这不是主要原因。紧接着那句话之后,视频中嵌入了一个问题:“为什么使用MergeSort作为参考类型?” (因为它很稳定)。我认为Sedgewick并没有在视频中提及这一点,以供质疑。
2015年

1

java.util.Arrays使用quicksort为原始类型如int和归并为实现对象可比或使用比较器。使用两种不同方法的想法是,如果程序员使用的对象空间可能不是至关重要的考虑因素,那么mergesort所使用的额外空间可能就不是问题,并且如果程序员使用的是原始类型,那么性能可能是最重要的事情。在快速排序

例如:这是排序稳定性很重要的示例。

在此处输入图片说明

这就是为什么稳定排序对对象类型有意义,尤其是可变对象类型和具有比排序键更多的数据的对象类型的原因,而mergesort就是这样的排序。但是对于原始类型,稳定性不仅无关紧要。没有意义的

资源: INFO


0

Java的Arrays.sort方法使用快速排序,插入排序和合并排序。OpenJDK代码中甚至实现了单轴和双轴快速排序。最快的排序算法取决于情况,而优胜者是:小数组的插入排序(当前选择47个),大多数排序的数组的mergesort和其余数组的快速排序,因此Java的Array.sort()尝试选择最佳算法来根据这些标准申请。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.