什么是大O符号?你用它吗?

时间:2008-09-25 12:29:50

标签: optimization complexity-theory big-o

什么是大O符号?你用它吗?

我猜错了这个大学课:D

有没有人使用它并提供一些他们使用它的真实例子?


另见:

Big-O for Eight Year Olds?
Big O, how do you calculate/approximate it?
Did you apply computational complexity theory in real life?

12 个答案:

答案 0 :(得分:31)

大多数人在谈论Big-O时会忘记一件重要的事情,因此我觉得有必要提一下:

您不能使用Big-O来比较两种算法的速度。 Big-O只表示如果你将处理的项目数增加一倍,算法将获得多少(大约),或者如果你将数字减半,它将获得多快的速度。

但是,如果您有两个完全不同的算法,其中一个(A)为O(n^2)而另一个(B)为O(log n),则不会说AB慢。实际上,对于100个项目,A可能比B快十倍。它只表示有200个项目,A会因因子n^2而变慢,而B会因因子log n而变慢。因此,如果您对两者都进行基准测试,并且知道A处理100个项目需要多长时间,以及相同的100个项目需要多长时间B,并且A比{B更快1}},您可以计算B项的速度超过A的项目数量(因为B的速度比A的速度慢得多,所以迟早会超过A - 这是肯定的。)

答案 1 :(得分:8)

Big O表示法表示算法的限制因素。它简化了算法运行时间与输入相关的缩放表达式。

例如(在Java中):

/** Takes an array of strings and concatenates them
  * This is a silly way of doing things but it gets the 
  * point across hopefully
  * @param strings the array of strings to concatenate
  * @returns a string that is a result of the concatenation of all the strings
  *          in the array
  */
public static String badConcat(String[] Strings){
    String totalString = "";
    for(String s : strings) {
        for(int i = 0; i < s.length(); i++){
            totalString += s.charAt(i);
        }
    }
    return totalString;
}

现在想想这实际上在做什么。它会遍历输入的每个字符并将它们添加到一起。这似乎很简单。问题是 String是不可变的。因此,每次在字符串上添加字母时,都必须创建一个新字符串。为此,您必须将旧字符串中的值复制到新字符串中并添加新字符。

这意味着您将复制第一个字母 n 次,其中 n 是输入中的字符数。您将复制字符n-1次,因此总共会有(n-1)(n/2)份副本。

这是(n^2-n)/2,对于Big O表示法,我们只使用最高幅度因子(通常)并删除任何乘以它的常数,最后得到O(n^2)

使用像StringBuilder这样的东西将沿着O(nLog(n))。如果您计算开头的字符数并设置StringBuilder的容量,则可以将其设为O(n)

因此,如果我们有1000个字符的输入,第一个示例将执行大约一百万个操作,StringBuilder将执行10,000个,StringBuildersetCapacity将执行1000个操作同一件事情。这是粗略估计,但O(n)符号是关于数量级的,而不是精确的运行时间。

这不是我经常说的。然而,当我试图找出做某事的最佳算法时,它始终处于我的脑海中。

答案 2 :(得分:4)

Big-O for Eight Year Olds?已经提出了一个非常类似的问题。希望那里的答案能回答你的问题,虽然问题提问者确实有一些关于它的数学知识,如果你需要更全面的解释,你可能没有这样澄清。

答案 3 :(得分:3)

每个程序员都应该知道Big O符号是什么,它如何应用于具有通用数据结构和算法的操作(从而为他们正在解决的问题选择正确的DS和算法),以及如何为他们计算它们自己的算法。

1)这是在处理数据结构时测量算法效率的顺序。

2)像'add'/'sort'/'remove'这样的操作可能会花费不同的时间与不同的数据结构(和算法),例如'add'和'find'是散列映射的O(1) ,但O(log n)为二叉树。对于QuickSort,Sort是O(nlog n),但在处理普通数组时,对于BubbleSort是O(n ^ 2)。

3)计算通常可以通过查看算法的循环深度来完成。没有循环,O(1),循环迭代所有集合(即使它们在某一点突破)O(n)。如果循环在每次迭代时将搜索空间减半? O(log n)。取一个循环序列的最高O(),并在嵌套循环时乘以O()。

是的,它比那更复杂。如果你真的有兴趣获得一本教科书。

答案 4 :(得分:3)

'Big-O'符号用于比较变量的两个函数(比如n)的增长率,因为n非常大。如果函数f比函数g增长得快得多,我们说g = O(f)意味着对于足够大的n,f将总是大于g直到缩放因子。

事实证明,这在计算机科学中是一个非常有用的想法,尤其是在算法分析中,因为我们经常关注函数的增长率,这些函数代表了两种不同算法所花费的时间。非常粗略地,我们可以确定具有运行时间t1(n)的算法比具有运行时间t2(n)的算法更有效,如果t1 = O(t2)足够大的n(通常是'大小')问题 - 如数组的长度或图中的节点数或其他。

这个规定,n足够大,允许我们提取很多有用的技巧。也许最常用的一种方法是,您可以将功能简化为增长最快的条款。例如n ^ 2 + n = O(n ^ 2)因为当n变得足够大时,n ^ 2项比得到大得多,n项实际上是无关紧要的。所以我们可以不考虑它。

然而,它确实意味着大O符号对于小n来说不太有用,因为我们忘记的增长较慢的术语仍然足以影响运行时。

我们现在拥有的是一种用于比较两种不同算法的成本的工具,以及一种说明一种比另一种更快或更慢的简写。 Big-O符号可以被滥用,这是一种耻辱,因为它已经不够精确了!有相同的术语表示函数的增长速度低于另一个函数,并且两个函数以相同的速率增长。

哦,我是否使用它?是的,所有的时间 - 当我弄清楚我的代码是多么有效时,它给出了一个很好的'背包 - 近似成本。

答案 5 :(得分:3)

Big-O背后的“Intuitition”

想象一下x上两个函数之间的“竞争”,因为x接近无穷大:f(x)和g(x)。

现在,如果从某个点(某些x)开始,一个函数的值总是高于另一个函数,那么让我们称这个函数比另一个函数“更快”。

因此,例如,如果每个x&gt; 100你看到f(x)&gt; g(x),则f(x)比g(x)“更快”。

在这种情况下,我们会说g(x)= O(f(x))。 f(x)对g(x)构成了一种“速度限制”,因为它最终会通过它并将其留下来。

这不完全是big-O notation的定义,它也指出f(x)只需要大于C * g(x)的某些常数C(这只是另一种说法你不能帮助g(x)通过乘以一个常数因子来赢得比赛 - f(x)最终会赢得比赛)。形式定义也使用绝对值。但我希望我设法让它变得直观。

答案 6 :(得分:2)

也许值得考虑的是,许多算法的复杂性基于多个变量,特别是在多维问题中。例如,我最近不得不为以下内容编写算法。给定一组n个点和m个多边形,提取位于任何多边形中的所有点。复杂性基于两个已知变量n和m,以及每个多边形中有多少个点的未知数。这里的大O符号比O(f(n))或甚至O(f(n)+ g(m))更复杂。 当你处理大量同质物品时,大O是好的,但不要指望总是如此。

值得注意的是,数据上的实际迭代次数通常取决于数据。 Quicksort通常很快,但是给它预分类数据并且速度变慢。基于先前对数据如何组织的知识以及n和m的相对大小,我的点和多边形算法结果非常快,接近于O(n +(m log(m))。它会下降严重随意组织不同相对大小的数据。

最后要考虑的是,算法的速度与其使用的空间量之间经常存在直接的折衷。 Pigeon hole sorting就是一个非常好的例子。回到我的点和多边形,让我们说我的所有多边形都很简单快速地绘制,我可以在屏幕上画出它们,比如蓝色,每个都有固定的时间。因此,如果我在黑色屏幕上绘制m个多边形,则需要O(m)时间。要检查我的n个点是否在多边形中,我只需检查该点的像素是绿色还是黑色。因此检查是O(n),总分析是O(m + n)。当然,如果我处理的是真实世界坐标以达到毫米级精度,我需要接近无限存储...... ......哼哼。

答案 7 :(得分:2)

也许值得考虑摊销时间,而不仅仅是最坏情况。这意味着,例如,如果您运行算法 n 次,它将平均 O(1),但有时可能会更糟。

一个很好的例子是动态表,它基本上是一个在向其添加元素时展开的数组。对于每个添加的元素,天真的实现会将数组的大小增加1,这意味着每次添加新元素时都需要复制所有元素。如果使用此方法连接一系列数组,这将导致 O(n 2 算法。另一种方法是每次需要更多存储时将阵列容量加倍。即使附加有时是 O(n)操作,您只需为每个添加的 n 元素复制 O(n)元素,所以操作平均为 O(1)。这就是 StringBuilder std :: vector 之类的实现方式。

答案 8 :(得分:2)

什么是大O符号?

Big O表示法是一种表达算法需要与输入数据大小相关的许多步骤之间关系的方法。这被称为算法复杂性。例如,使用冒泡排序对大小为N的列表进行排序需要O(N ^ 2)步。

我是否使用Big O表示法?

我偶尔会使用Big O表示法来向其他程序员传达算法的复杂性。当我考虑使用什么算法时,我总是使用基础理论(例如Big O分析技术)。

具体例子?

我使用复杂性分析理论为高效的堆栈数据结构创建算法,这些算法不需要内存重新分配,并且支持索引的平均O(N)时间。我使用Big O表示法向其他人解释算法。我还使用复杂性分析来理解线性时间排序O(N)何时是可能的。

答案 9 :(得分:1)

来自维基百科.....

在分析算法以提高效率时,Big O表示法非常有用。例如,完成大小为n的问题所需的时间(或步数)可能是T(n)=4n² - 2n + 2.

当n变大时,n 2项将占主导地位,因此所有其他项都可以忽略 - 例如当n = 500时,项4n²是2n项的1000倍。在大多数情况下,忽略后者对表达式的价值可以忽略不计。

显然我从未使用它..

答案 10 :(得分:1)

您应该能够评估算法的复杂性。这结合了它将采取多少元素的知识可以帮助您确定它是否适合它的任务。

答案 11 :(得分:0)

它表示在最坏的情况下算法有多少次迭代。

要搜索列表中的项目,您可以遍历列表,直到获得该项目。在最坏的情况下,该项目位于最后一位。

让我们说列表中有n个项目。在最坏的情况下,你需要进行n次迭代。在Big O中,它是O(n)。

事实上说,算法的效率如何。