【问题标题】:Which sorting algorithm works best on very large data set [closed]哪种排序算法在非常大的数据集上效果最好[关闭]
【发布时间】:2015-08-26 19:04:44
【问题描述】:

我在 Internet 上搜索以查找哪种排序算法最适合非常大的数据集。我发现许多人认为合并排序是最好的,因为它是公平的,并且它确保时间复杂度为 O(n log n) 并且快速排序不安全:快速排序的变体也可以不安全,因为真实的数据集可以是任何东西。

如果交换两个元素的时间成本可以忽略不计,那么为什么我们不能选择堆排序作为这种情况下的最佳排序算法,因为它和 O(n log n) 一样到位?

在合并排序的情况下,它需要另一个 O(n) 空间;如果数据非常大,我们就不能使用这个算法。

请告诉我:在这种情况下哪种算法应该是最好的?

【问题讨论】:

  • “非常大”相当模糊。
  • 链表上的合并排序占用固定空间并且仍然是稳定的,因此您对空间的担忧可能无效。它还可以很好地处理文件,并且可以利用多个处理器。
  • sorting-algorithms.com 有趣地展示了所涉及的一些变量和权衡。
  • @erickson 它真的使用 O(1) 辅助空间吗?我认为您需要 O(log n) 空间来存储调用堆栈。
  • @templatetypedef 不,这是一个 O(1) 空间的迭代算法。只需几个指针和几个计数器。

标签: algorithm sorting


【解决方案1】:

没有一种算法显然是“最佳”算法。如果有,我们会在任何地方使用它!相反,它取决于一系列因素。

首先,您能否将数据放入主内存中?如果不能,则需要依赖外部排序算法。这些算法通常基于快速排序和归并排序。

其次,你对你的输入分布有什么了解吗?如果它主要是排序的,那么像 Timsort 这样的东西可能是一个不错的选择,因为它旨在很好地处理排序的数据。如果它主要是随机的,那么 Timsort 可能不是一个好的选择。

第三,你排序的是什么元素?如果您正在对通用对象进行排序,那么您几乎被锁定在比较排序中。如果没有,也许您可​​以使用非比较排序,例如计数排序或基数排序。

第四,你有多少个核心?一些排序算法(快速排序、归并排序、MSD 基数排序)并行性非常好,而其他排序算法(堆排序)则不然。

第五,您的数据是如何表示的?如果它们存储在数组中,快速排序或快速排序变体可能会因为引用的局部性而表现良好,而由于需要额外的内存,合并排序可能会很慢。但是,如果它们在一个链表中,那么来自快速排序的引用局部性就会消失,并且合并排序会突然再次变得具有竞争力。

最好的选择可能是考虑很多不同的因素,然后从那里做出决定。设计和研究算法如此有趣的原因之一是很少有一个单一的最佳选择。通常,最佳选择在很大程度上取决于您的具体情况,并根据您所看到的情况进行更改。

(在结束这个答案之前,您提到了一些关于快速排序、堆排序和合并排序的细节。虽然您是对的,但快速排序有一个退化的 O(n2)最坏的情况,有很多方法可以避免这种情况。引入排序算法会跟踪递归深度,如果快速排序看起来会退化,则将算法切换到堆排序。这保证了 O(n log n) 内存不足的最坏情况行为开销并最大限度地提高您从快速排序中获得的收益。随机快速排序虽然仍然有 O(n2) 最坏情况,但实际遇到最坏情况的可能性非常小。

堆排序在实践中是一种很好的算法,但在某些情况下不如其他算法快,因为它没有良好的参考局部性。也就是说,它永远不会退化并且只需要 O(1) 辅助空间这一事实是一个巨大的卖点。

Mergesort 确实需要大量辅助内存,这就是如果您有大量数据要排序时您可能不想使用它的原因之一。不过,值得了解一下,因为它的变体被广泛使用。)

【讨论】:

  • +1。当涉及多台机器时,或者当您必须考虑从磁盘或网络访问数据的时间时,它会变得更加有趣。
  • @rcgldr 我所指的快速排序变体通过内存流式传输文件内容来工作,维护一个巨大的双端优先级队列。当队列填满时,太小的元素被逐出并写入“更少”文件,太大的元素被逐出并写入“更大”文件。最终的队列内容,然后写入“pivot”文件,然后对较小和较大的文件进行递归排序。它不像合并排序变体那样常见,但我相信它仍然有效。
  • @templatetypedef - Wiki 文章 external sorting。 k 路底部合并排序可以使用 wiki 文章中提到的大型顺序 I/O,这有助于减少硬盘驱动器上的寻道开销,但在 SSD 驱动器的情况下,没有真正的寻道开销(内部布局重新映射以减少对特定区域的写入计数),因此快速排序可能是一种可行的选择,尽管它不稳定。维基文章中没有提到它。
  • @rcgldr 我没有考虑过 SSD。至于快速排序,请查看this site,IIRC 也是一本书的章节。
  • @templatetypedef - 我为快速排序找到的参考文献提到了 O(n log(n)) 的良好时间复杂度,但没有提到什么 log。对于k路归并排序,最坏情况的时间复杂度是O(n logk(n));我的猜测是,如果 k == 8 或 k == 16,它会比快速排序快得多。同样在我在原帖后的评论中提到,快速排序进行更多比较,合并排序更多移动,如果按索引或指针对某种类型的结构进行排序,合并排序通常比快速排序更快。
【解决方案2】:

您的问题过于开放,无法具体回答。有许多有效的排序算法,每一种都有自己的长处和短处。如果您了解自己的数据,那么最佳效率算法(堆、快速、合并等)可能不是适合这项工作的工具。

例如,在最近的一个产品中,我们需要将书签保存在 Word 文档中,按其出现顺序排序。由于文档的编辑(复制、剪切、粘贴),书签可能会变得未排序,因此在每次这些操作之后,重新使用列表很重要。在这种情况下,冒泡排序是正确的答案,尽管它的大 O 复杂度高于任何数量的其他算法。当列表接近排序时排序是有效的(在这种情况下通常是这种情况),并且它是就地操作,这意味着它是完成这项工作的正确工具。

仔细查看您的数据并阅读知名排序算法的各种优势和劣势,您就可以很好地回答自己的问题。

【讨论】:

  • 非常感谢您的解释,我一定会寻找的
猜你喜欢
  • 1970-01-01
  • 2012-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
相关资源
最近更新 更多