为什么Collections.sort使用合并排序而不是快速排序?

时间:2013-03-01 09:12:56

标签: java sorting collections

我们知道快速排序是最快的排序算法。

collections.sort使用合并排序算法而不是快速排序。但是Arrays.sort使用快速排序。

Collections.sort使用合并排序而不是快速排序的原因是什么?

1 个答案:

答案 0 :(得分:172)

极有可能来自Josh Bloch §

  

我确实写过这些方法,所以我想我有资格回答。它是   确实没有单一的最佳排序算法。 QuickSort有   与mergesort相比有两个主要缺陷:

     
      
  1. 它不稳定(正如parsifal所说)。

  2.   
  3. 它不保证 n log n性能;它可以降低到病理输入的二次性能。

  4.         

    稳定性对于原始类型来说不是问题,因为没有概念   身份与(价值)平等不同。和可能性   二次行为在实践中被认为不是一个问题   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?

没有一个“最佳”选择。与许多其他事情一样,这是权衡利弊。