【问题标题】:Are O(n log n) algorithms always better than all O(n^2) algorithms?O(n log n) 算法总是优于所有 O(n^2) 算法吗?
【发布时间】:2018-05-27 21:15:48
【问题描述】:

在尝试正确理解 Big-O 时,我想知道 O(n log n) 算法是否总是优于 all O(n^2) 算法。

在某些特殊情况下O(n^2) 会更好吗?

我多次阅读过,例如在排序中,像冒泡排序这样的O(n^2) 算法在数据几乎排序时会特别快,那么它会比O(n log n) 算法(比如合并排序)更快吗,在这种情况下?

【问题讨论】:

  • 尝试使用朴素的“schoolchild”方法(O(n^2))编写 n 位数乘法的代码,然后尝试使用 Schönhage–Strassen 算法来实现它(仅比 O 稍差一点) (n log n))。你会发现朴素的方法在实现难度上有一些优势:)

标签: algorithm time-complexity big-o


【解决方案1】:

不,O(n log n) 算法并不总是比O(n^2) 更好。 Big-O 表示法描述了算法渐近行为的上限,即n趋于无穷大。

在这个定义中你必须考虑一些方面:

  1. Big-O 表示法是算法复杂度的上限,这意味着对于某些输入(例如您提到的排序算法),具有最差 Big-O 复杂度的算法实际上可能表现更好(冒泡排序在 @ 987654323@ 用于已经排序的数组,而 mergesort 和 quicksort 总是至少需要 O(n log n));
  2. Big-O 表示法仅描述复杂性类别,隐藏了在实际情况下可能相关的所有常量因素。例如,对于小于 2000000 的输入,具有复杂度 1000000 x 的算法在类 O(n) 中的性能比复杂度 0.5 x^2 的算法(类 O(n^2))最差。基本上,Big-O 表示法告诉您对于足够大的输入 n,O(n) 算法的性能将优于 O(n^2),但如果您使用较小的输入,您可能仍然更喜欢后一种解决方案。

【讨论】:

    【解决方案2】:

    O(n log n) 优于 O(n2) 渐近

    Big-O、Big-Theta、Big-Omega,所有这些都测量函数的渐近行为,即当参数接近某个极限时函数的行为。

    O(n log n) 函数比 O(n2) 函数增长得慢,这就是 Big-O 表示法本质上所说的。然而,这并不意味着 O(n log n)总是更快。这仅仅意味着在某个时候,对于不断上升的 n 值,O(n log n) 函数总是会更便宜。

    在该图像中,f(n) = O(g(n))。请注意,在一个范围内 f(n) 实际上比 g(n) 更昂贵,即使它是由 g(n) 渐近限定的。然而,当谈到极限,或就此而言的渐近线时,可以说,“从长远来看”,f(n) 优于 g(n)。

    【讨论】:

    • 我明白这一点,但我不明白 O(n^2) 比 O(n log n) 更好的可能情况以及这是如何可能的(忽略硬件问题等)?
    • @Laura 取一个描述程序运行时间的函数,它首先打印出从 1 到 10^100 的所有数字,然后对输入执行归并排序:T(n) = O( n 对数 n) + c。 c 在这里是一个常数因子,它是 huge:毕竟,我们打印的是 1 到 10^100!但是,它是一个常数,因为它与输入大小 n 无关。然而,T(n) 是 O(n log n)!现在采用一个简单的冒泡排序算法,它在 O(n^2) 中运行。哪个会更快?
    【解决方案3】:

    除了@cadaniluk 的回答:

    如果您将算法的输入限制为非常特殊的类型,这也会影响运行时间。例如。如果你只在已经排序的列表上运行排序算法,BubbleSort 将在线性时间内运行,但 MergeSort 仍然需要 O(n log n)。 还有一些算法的最坏情况复杂度很差,但平均情况复杂度很好。这意味着存在错误的输入实例,因此算法很慢,但总的来说,您不太可能遇到这种情况。

    永远不要忘记,Big-O 表示法隐藏了常数和低阶的加法函数。因此,具有最坏情况复杂度 O(n log n) 的算法实际上可能具有 2^10000 * n * log n 的复杂度,而您的 O(n^2) 算法实际上可以在 1/2^1000 n^2 中运行。所以对于 n

    【讨论】:

      【解决方案4】:

      这是一个实际的例子。 排序函数的 GCC 实现具有 O(n log n) 复杂度。尽管如此,只要被排序的部分的大小小于某个小常数,他们就会使用 O(n^2) 算法。 这是因为对于小尺寸,它们在实践中往往更快。

      See here 用于一些内部实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-25
        • 1970-01-01
        相关资源
        最近更新 更多