一个很好的排序算法,用于大部分排序的数据,但并不完全适合内存? [关闭]

Posted

技术标签:

【中文标题】一个很好的排序算法,用于大部分排序的数据,但并不完全适合内存? [关闭]【英文标题】:A good sorting algorithm for mostly-sorted data that doesn't all fit into memory? [closed] 【发布时间】:2012-03-18 14:07:57 【问题描述】:

如果你得到:

一定数量的数据 内存大小是数据大小的一半 部分数据已排序 您不知道已排序数据的大小。

你会选择哪种排序算法? 我在插入和快速排序之间争论。我知道插入排序的最佳情况是 O(n),但最坏的情况是 O(n2)。此外,考虑到内存有限的事实,我会将数据分成两部分,并对它们进行快速排序,然后将所有内容合并在一起。拆分数据需要 O(n) 时间,合并数据需要 O(n) 时间,使用快速排序对数据进行排序需要 O(n log n) 时间,净运行时间为 O(n log n)。

有人对如何改进有任何建议吗?

【问题讨论】:

这是作业吗?它有一种家庭作业的气息。 你应该考虑把这个放到程序员部分。 不,正在修改数据结构。我刚刚从 UCBerkley 的你的管子上发现了一些很棒的课程,我正在尝试用排序算法锻炼自己。 @Rudy 只是数据结构 @Mohamed 但是堆排序需要一个数组,这意味着我拥有的所有数据的数组会超过我的内存大小吗?还是我仍然应该划分数据,然后使用堆排序对它们进行排序?无论如何,它不会仍然是相同的时间复杂度吗? 【参考方案1】:

您的类似合并排序的方法似乎非常合理。更一般地说,这种类型的排序算法称为external sorting algorithm。这些算法通常如您所描述的那样工作 - 将一些数据子集加载到内存中,对其进行排序,然后将其写回磁盘。最后,使用合并算法将所有内容重新合并在一起。选择加载多少以及使用什么排序算法通常是主要问题。我将主要关注排序算法的选择。

您对快速排序的最坏情况行为的担忧一般而言没什么好担心的,因为如果您随机选择枢轴,那么您获得非常糟糕的运行时的可能性很低。即使数据已经排序,随机枢轴策略也能很好地工作,因为它没有最坏情况的输入(除非有人知道你的随机数生成器和种子)。您还可以使用像 introsort 这样的快速排序变体,它没有最坏情况的行为,作为您的排序算法,以避免这种最坏情况。

也就是说,由于您知道数据已经部分排序,您可能需要查看adaptive sorting algorithm 以进行排序步骤。您已经为此提到了插入排序,但是那里有更好的自适应算法。如果内存不足(正如您所描述的),您可能想尝试查看 smoothsort 算法,该算法具有最佳情况运行时间 O(n),最坏情况运行时间 O(n log n),并且仅使用 O(1) 内存。它不像其他一些算法(如 Python 的 timsort、natural mergesort 或 Cartesian tree sort)那样自适应,但它的内存使用率较低。它也没有一个好的快速排序那么快,但如果数据真的大部分都是排序的,它可以做得很好。

希望这会有所帮助!

【讨论】:

【参考方案2】:

从表面上看,我会用快速排序分而治之,然后收工。许多算法问题都被过度思考了。

现在,如果您确实有要使用的测试数据并且真的想掌握它,请在中间添加一个抽象类并进行基准测试。我们可以整天胡思乱想,但知道数据已经部分排序,您必须进行测试。在大多数快速排序实现中,已排序的数据会带来最坏情况下的性能。

考虑有many sorting algorithms,其中一些更适合排序集。此外,当您知道一个集合已排序时,您可以在 n 时间内将其与另一个集合合并。因此,当您比较添加单个 (n) 通道时,首先识别已排序数据块可能会为您节省大量时间,并大大减少快速排序进入 (n2) 时间的机会。

【讨论】:

没错,完全忘记了快速排序对排序数据的表现不佳。 也就是说,通过使用不同的旋转策略(例如,随机选择),可以轻松地修改快速排序,以在已排序的序列上不出现这种异常情况。 他说他无法将数据放入内存中,所以快速排序不是一个好的选择。 @Joel- 不过,您可以快速排序适合内存的数据块,然后将它们合并在一起。这是一个完全合理的方法。 @Joel:“分而治之”...由于速度和内存原因,最后合并的并行快速排序块非常常见。

以上是关于一个很好的排序算法,用于大部分排序的数据,但并不完全适合内存? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

地图聚类算法

C++ 八大排序之一-----快速排序

并行排序算法

java排序算法:直接插入排序

常见的排序算法总结(JavaScript)

排序——快速排序算法