我们知道快速排序是最快的排序算法。
collections.sort使用合并排序算法而不是快速排序。但是Arrays.sort使用快速排序。
Collections.sort使用合并排序而不是快速排序的原因是什么?
答案 0 :(得分:172)
极有可能来自Josh Bloch §:
我确实写过这些方法,所以我想我有资格回答。它是 确实没有单一的最佳排序算法。 QuickSort有 与mergesort相比有两个主要缺陷:
它不稳定(正如parsifal所说)。
- 醇>
它不保证 n log n性能;它可以降低到病理输入的二次性能。
稳定性对于原始类型来说不是问题,因为没有概念 身份与(价值)平等不同。和可能性 二次行为在实践中被认为不是一个问题 Bentely和McIlroy的实现(或随后用于Dual Pivot Quicksort),这就是为什么这些QuickSort变体用于 原始的种类。
在对任意对象进行排序时,稳定性是一个大问题。例如, 假设您有表示电子邮件的对象,并进行排序 他们先按日期,然后按寄件人。你希望它们按顺序排序 每个发件人中的日期,但只有在排序的情况下才会成立 稳定。这就是我们选择提供稳定排序(合并排序)的原因 排序对象引用。 (从技术上讲,多个顺序 稳定的排序导致对词中的键的词典排序 排序的相反顺序:最终排序决定最多 重要的子项。)
Merge Sort 保证 n log n(时间)这是一个很好的附带好处 性能无论输入什么。当然有一个不利方面: 快速排序是一种“就地”排序:它只需要记录外部空间 (维护调用堆栈)。另一方面,合并,排序, 需要O(n)外部空间。 TimSort变体(在Java中引入) 如果输入阵列是,则SE 6)需要的空间(O(k))要小得多 几乎排序。
此外,following是相关的:
java.util.Arrays.sort和(间接)使用的算法 java.util.Collections.sort对对象引用进行排序是“修改过的 mergesort(如果最高元素,则省略合并 低子列表小于高子列表中的最低元素。“它 是一个相当快速稳定的排序,保证O(n log n) 性能并需要O(n)额外空间。在它的日子(它写了 在1997年由约书亚布洛赫,这是一个很好的选择,但今天,但我们可以 做得更好。
自2003年以来,Python的列表排序使用了一种名为timsort的算法 (在撰写之后的蒂姆彼得斯之后)。它是一种稳定的,自适应的迭代 mergesort,需要远远少于n log(n)比较时 在部分排序的阵列上运行,同时提供性能 与随机数组上运行的传统mergesort相当。喜欢 所有正确的mergesorts timsort是稳定的并且在O(n log n)时间内运行 (最糟糕的情况)。在最坏的情况下,timsort需要临时存储 n / 2个对象引用的空间;在最好的情况下,它只需要一个 小的恒定空间。与此相反 实现,总是需要额外的空间用于n个对象 引用,仅在近乎排序的列表上击败n log n。
Timsort在这里有详细描述: http://svn.python.org/projects/python/trunk/Objects/listsort.txt
Tim Peters最初的实现是用C. Joshua Bloch编写的 将它从C移植到Java并最终测试,基准测试和调整 结果代码广泛。生成的代码是一个插件 替换java.util.Arrays.sort。在高度有序的数据上,这个 代码的运行速度最高可达当前实现的25倍(on HotSpot服务器VM)。随机数据,新旧速度 实现具有可比性。对于非常短的名单,新的 实现大大快于老即使随机 数据(因为它避免了不必要的数据复制)。
另请参阅Is Java 7 using Tim Sort for the Method Arrays.Sort?。
没有一个“最佳”选择。与许多其他事情一样,这是权衡利弊。