O(n)算法在计算时间方面是否可以超过O(n ^ 2)?

Bri*_*ian 60 complexity-theory big-o time-complexity

假设我有两种算法:

for (int i = 0; i < n; i++) {
  for (int j = 0; j < n; j++) {
    //do something in constant time
  }
}
Run Code Online (Sandbox Code Playgroud)

这很自然O(n^2).假设我也有:

for (int i = 0; i < 100; i++) {
  for (int j = 0; j < n; j++) {
    //do something in constant time
  }
}
Run Code Online (Sandbox Code Playgroud)

这是 O(n) + O(n) + O(n) + O(n) + ... O(n) + = O(n)

似乎即使我的第二个算法是O(n),它也需要更长的时间.有人可以扩展吗?我提出它是因为我经常看到算法,例如,他们将首先执行排序步骤或类似的事情,并且在确定总复杂度时,它只是限制算法的最复杂元素.

Duk*_*ing 98

渐近复杂度(这是大O和大Theta所代表的)完全忽略了所涉及的常数因素 - 它仅用于指示随着输入的大小变大,运行时间将如何变化.

因此,对于某些给定的?(n)算法,一个算法可能需要花费的时间超过一个- 这将会发生真正取决于所涉及的算法 - 对于您的具体示例,这将是这种情况,忽略了优化之间的差异的可能性二.?(n2)nnn < 100

对于任何两个给定的算法?(n)和时间,你可能会看到的是:?(n2)

  • ?(n)算法在n较小时较慢,然后随着增加而变慢 (如果一个更复杂,即具有更高的常数因子,则会发生),或者?(n2)n
    ?(n)
  • 在一个总是慢.?(n2)

虽然这当然可能,该?(n)算法可以慢,那么一个,然后又一个,依此类推为增加,直到变得非常大,从该点起一个将永远是慢的,虽然它是大大不太可能发生.?(n2)?(n)nn?(n2)

稍微更多的数学术语:

假设算法对某些算法采取操作.?(n2)cn2c

并且?(n)算法dn为某些操作采取操作d.

这与形式定义一致,因为我们可以假设它保持n大于0(即对于所有n)并且运行时间所在的两个函数是相同的.

在你的榜样行,如果你是说c = 1d = 100,则?(n)算法将变得更慢,直到n = 100,在该点算法将变得更慢.?(n2)

(由WolframAlpha提供).

符号说明:

技术上,big-O只是一个上限,这意味着你可以说一个O(1)算法(或者实际上任何算法花费的时间或更少的时间).因此我改为使用big-Theta(Θ)符号,这只是一个紧密的约束.有关更多信息,请参阅正式定义.O(n2)O(n2)

Big-O经常被非正式地视为或被教导成为一个紧张的界限,所以你可能已经基本上使用了big-Theta而不知道它.

如果我们只谈论一个上限(根据big-O的正式定义),那就更像是一个"任何事情"的情况 - O(n)一个可以更快,一个可以更快或者他们可以采取相同的时间量(渐近) - 关于比较算法的大O,通常不能做出特别有意义的结论,只能说,给定一些算法的大O,该算法不会采取任何算法比这个时间长(渐近).O(n2)

  • 作为一个具体的例子,对于小输入,插入排序(O(n ^ 2))比Quicksort(O(nlogn))快,并且[通常用作小输入的"基本情况"](http:// en .wikipedia.org /维基/快速排序#优化).另请注意,插入排序是一个有趣的例子,说明天真的渐近分析可能会失败.它在最坏的情况下以O(n ^ 2)运行,但是对于"大多数"排序的列表而言是O(n)时间.这是因为它实际上在O(反转的#)中运行. (14认同)
  • @JFSebastian然后它以错误的方式使用,在科学家和从业者之间创造了不必要的障碍.只需使用Θ,因为它通常是你(即程序员)想要的(你*应该*想要更精确的陈述,但那是另一次).(维基百科的文章表明,这种做法在CS中广泛传播.虽然不幸的是,这并不能使其正确:通常发生此错误的人是a)不了解事实(不好)或b)草率(更糟) .) (5认同)
  • @Raphael:在编程中,[`O(n)`经常用作Θ(n)](http://en.wikipedia.org/wiki/Big_O_notation#Use_in_computer_science) (3认同)
  • @Raphael它真的不是特别重要,你正在处理语义.程序员希望能够说"我的算法是O(无论如何)".对他来说这意味着,我的算法可能不比这慢,这是重要的.特别是因为要求可能通常是O格式,只是因为他们说"我们至少需要这个,所以证明它是O(f(n)),我们很高兴".证明theta通常是多余的. (2认同)

Nik*_*nka 19

是的,O(n )算法在运行时间方面可以超过O(n 2)算法.当常数因子(我们在大O表示法中省略)很大时会发生这种情况.例如,在上面的代码中,O(n)算法将具有很大的常数因子.因此,它将比在O(n 2)中运行n <10 的算法表现更差.

这里,n = 100是交叉点.因此,当任务可以在O(n)和O(n 2)中执行并且线性算法的常数因子大于二次算法的常数因子时,那么我们倾向于优选具有更差运行时间的算法.例如,在对数组进行排序时,我们会切换到较小数组的插入排序,即使合并排序或快速排序运行渐进式更快.这是因为插入排序的常数因子比合并/快速排序小,并且运行速度更快.

  • 没关系.我在发布问题的几分钟内写的stackoverflow的第一个答案.我猜我需要提高打字速度. (3认同)
  • Big-O只给出一个粗略的想法,并确定渐近行为.如果差异较小,比如说O(n)对O(n log n),则常数更为重要 - 一个程序需要100n纳秒,实际上永远不会快于一个(n nn)纳秒(如果你计算交叉点,未来将是几百万年). (2认同)

hiv*_*ert 17

O(n)并不是要比较不同算法的相对速度.它们用于测量当输入大小增加时运行时间增加的速度.例如,

  • O(n)表示如果n乘以1000,则运行时间大致乘以1000.
  • O(n^2)表示如果n乘以1000,则运行大致乘以1000000.

因此,当n足够大时,任何O(n)算法都会击败O(n^2)算法.它并不意味着任何固定的东西n.


Sav*_*ave 5

长话短说,是的,它可以.定义O是基于这样一个事实,即这O(f(x)) < O(g(x))意味着肯定g(x)会花费更多的时间来运行而不是f(x)给予足够大的支持x.

例如,一个已知的事实是,对于小值,合并排序优于插入排序(如果我没记错的话,那应该适用于n小于31)