在O(n * log(n))最坏的情况下排序

时间:2011-10-19 08:55:42

标签: algorithm sorting

是否存在一种在O(n * log(n))最坏情况时间复杂度下工作的数组?

我在维基百科中看到有类似的情况,但它们不稳定,这是什么意思?有没有办法在低空间复杂性?

是否有最佳排序算法?

6 个答案:

答案 0 :(得分:4)

一种只需要O(1)额外内存的算法(因此允许修改输入数组)通常被描述为“就地”,这是空间复杂度最低的。

排序被描述为“稳定”与否,根据当输入中有两个元素比较相等但在某种程度上可以区分时会发生什么。例如,假设您有一堆带有整数字段和字符串字段的记录,并在整数字段上对它们进行排序。问题是,如果两个记录具有相同的整数值但是字符串值不同,那么输入中第一个记录的记录也会在输出中排在第一位,或者它们是否可能会被反转?稳定排序是保证保持比较相同但不相同的元素顺序的排序。

难以进行就地比较排序,稳定,达到O(n log n)最坏情况时间复杂度。我有一个模糊的想法,不知道它是否可能,但我不及时了解它。

上次有人询问这个问题时,我发现了几篇相关的论文,虽然这个问题与这个问题不一样:

How to sort in-place using the merge sort algorithm?

就“最佳”排序而言 - 一些排序策略利用了这样一个事实:总的来说,在大量应用程序中,计算机花费大量时间对不随机洗牌的数据进行排序,它有一些结构。 Timsort是一种利用常见结构的算法。它在许多实际应用中表现很好。您无法将其描述为“最佳”类型,因为它是一种似乎在实践中表现良好的启发式方法,而不是对先前算法的严格改进。但是,对于那些将其作为默认排序(Python,Java 7,Android)的人来说,它是“最好的”。您可能不会将其描述为“低空间复杂度”,但它并不比标准的合并排序更好。

答案 1 :(得分:2)

您可以在mergesort,quicksort或heapsort之间查看所有精美描述的here

还有基数排序,其复杂度为O(kN),但它充分利用了额外的内存消耗。

您还可以see对于较小的集合,quicksort更快,但然后mergesort取得领先,但所有这些都是特定于案例的,所以花点时间研究所有4种算法

答案 2 :(得分:2)

对于问题最佳算法,简单的答案是取决于。这取决于您要排序的数据集的大小,这取决于您的要求.Say,冒泡排序具有最坏情况和平均复杂度О(n 2 ),其中n是被排序的项目数。存在许多具有明显更好的O(n log n)的最坏情况或平均复杂度的排序算法。甚至其他О(n 2 )排序算法(例如插入排序)往往具有比冒泡排序更好的性能。因此,当n很大时,冒泡排序不是一种实用的排序算法。

在简单的平均情况Θ(n 2 )算法中,选择排序几乎总是优于冒泡排序,但通常优于< em>插入排序。

选择排序在大型数组上大大优于Θ(n log n)分而治之的算法,例如 mergesort 。但是,对于小型数组,插入排序选择排序通常都更快。

同样,您可以根据自己的要求自行选择最佳排序算法。

答案 3 :(得分:1)

事实证明,O(n log n)是排序通用项的下限。还证明O(n)是排序整数的下限(至少需要读取输入:))。

问题的具体实例将确定什么是满足您需求的最佳算法,即。排序1M字符串不同于在2MB RAM中排序2M 7位整数。

还要考虑除了渐近运行时复杂性之外,实现还会产生很大的不同,以及可用内存和缓存策略的数量。

我可以在python中实现1行快速排序,大致保持O(n log n)的复杂性(关于枢轴的一些警告),但是Big-Oh表示法没有说明常量术语,这些术语也是相关的(即。这比python内置排序慢30倍,这很可能用C btw编写:

qsort = lambda a: [] if not a else qsort(filter(lambda x: x<a[len(a)/2], a)) + filter(lambda x: x == a[len(a)/2], a) + qsort(filter(lambda x: x>a[len(a)/2], a))

有关稳定/不稳定排序的讨论,请查看http://www.developerfusion.com/article/3824/a-guide-to-sorting/6/

您可能希望自己获得一本好的算法书(即Cormen或Skiena)。

答案 4 :(得分:1)

答案 5 :(得分:1)

关于你的问题意味着稳定,让我们考虑以下几点:我们有一类与年龄相关的孩子:

Phil, 10
Hans, 10
Eva, 9
Anna, 9
Emil, 8
Jonas, 10

现在,我们希望按照年龄上升的顺序对孩子进行排序(而不是其他任何事情)。然后,我们看到菲尔,汉斯和乔纳斯都已年满10岁,所以不清楚我们必须订购它们的顺序,因为我们按年龄排序

现在稳定了:如果我们对稳定进行排序,我们会按照他们之前的顺序对Phil,Hans和Jonas进行排序,即我们将Phil放在第一位,然后是Hans,最后是Jonas(仅仅是因为他们在原始序列中按此顺序排列,我们仅将年龄视为比较标准。同样地,我们必须把伊娃放在安娜之前(两个年龄相同,但是原来的顺序是伊娃在安娜面前)。

所以,结果是:

Emil, 8
Eva, 9
Anna, 9
Phil, 10   \
Hans, 10   | all aged 10, and left in original order.
Jonas, 10  /

简而言之:稳定性意味着如果两个元素相等(与所选择的排序标准相同),原始序列中首先出现的元素仍然在结果序列中排在第一位。 / p>

注意您可以轻松地将任何排序算法转换为稳定的排序算法:如果原始序列包含n元素:e1, e2, e3, ..., en,你只需在每个人附上一个计数器:(e1, 0), (e2, 1), (e3, 2), ..., (en, n-1)。这意味着您为每个元素存储其原始位置。

如果现在两个元素相等,则只需比较它们的计数器,然后首先将计数器置于较低的计数器值。这会使运行时(和内存)增加O(n)渐近没有恶化,因为最佳(比较)排序算法需要O(n lg n)