【问题标题】:What is Big O notation? Do you use it? [duplicate]什么是大 O 符号?你用它吗? [复制]
【发布时间】:2010-09-13 01:52:29
【问题描述】:

什么是大 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?

【问题讨论】:

  • 当然,每当我谈论我的爱情生活时

标签: optimization complexity-theory big-o


【解决方案1】:

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

您不能使用 Big-O 来比较两种算法的速度。 Big-O 仅说明如果将处理的项目数量加倍,算法会(大约)减慢多少,或者如果将数量减半,算法会变快多少。

但是,如果你有两种完全不同的算法,一种(A)是O(n^2),另一种(B)是O(log n),并不是说A比@987654326慢@。实际上,如果有 100 个项目,A 可能比B 快十倍。它只是说,对于 200 个项目,A 的增长速度会减慢 n^2 的因子,B 的增长速度会减慢 log n 的因子。因此,如果您对两者进行基准测试并且您知道 A 处理 100 个项目需要多少时间,以及 B 需要多少时间处理相同的 100 个项目,并且 AB 快,您可以计算为有多少项目B 将在速度上超过A(因为B 的速度比A 的速度慢得多,它迟早会超过A——这是肯定的)。

【讨论】:

    【解决方案2】:

    大 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,对于大 O 表示法,我们(通常)只使用最高幅度因子,并丢弃任何乘以它的常数,我们最终得到 O(n^2)

    使用StringBuilder 之类的东西将遵循 O(nLog(n))。如果计算开头的字符数并设置StringBuilder的容量可以得到O(n)

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

    这不是我经常使用的东西。然而,当我试图找出做某事的最佳算法时,它一直在我的脑海里。

    【讨论】:

      【解决方案3】:

      什么是大 O 符号?

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

      我是否使用大 O 表示法?

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

      具体例子?

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

      【讨论】:

        【解决方案4】:

        Big-O 背后的“直觉”

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

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

        因此,例如,如果对于每个 x > 100,您看到 f(x) > g(x),那么 f(x) 比 g(x)“快”。

        在这种情况下,我们会说 g(x) = O(f(x))。 f(x) 对 g(x) 构成了某种“速度限制”,因为最终它会通过它并永远离开它。

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

            还值得考虑的是,许多算法的复杂性都基于多个变量,尤其是在多维问题中。例如,我最近不得不为以下内容编写一个算法。给定一组 n 个点和 m 个多边形,提取位于任何多边形中的所有点。复杂性基于两个已知变量 n 和 m,以及每个多边形中有多少点的未知数。这里的大 O 表示法比 O(f(n)) 甚至 O(f(n) + g(m)) 要复杂得多。 当您处理大量同质项目时,Big O 是很好的选择,但不要期望总是如此。

            还值得注意的是,对数据的实际迭代次数通常取决于数据。快速排序通常很快,但给它预先排序的数据,它会变慢。我的点和多边形算法很快就结束了,接近 O(n + (m log(m)),基于对数据可能如何组织以及 n 和 m 的相对大小的先验知识。它会下降在不同相对大小的随机组织数据上表现不佳。

            最后要考虑的是,算法的速度和它使用的空间量之间通常存在直接的权衡。 Pigeon hole sorting 就是一个很好的例子。回到我的点和多边形,假设我所有的多边形都简单快速地绘制,我可以在屏幕上填充它们,比如用蓝色,每个固定的时间。因此,如果我在黑屏上绘制我的 m 个多边形,则需要 O(m) 时间。要检查我的任何 n 个点是否在多边形中,我只需检查该点的像素是绿色还是黑色。所以检查是O(n),总分析是O(m + n)。当然,缺点是,如果我要处理精确到毫米精度的现实世界坐标,我需要近乎无限的存储空间…………哼哼。

            【讨论】:

              【解决方案7】:

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

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

              这个规定,即 n 变得足够大,允许我们提取很多有用的技巧。也许最常用的一个是您可以将函数简化为增长最快的项。例如 n^2 + n = O(n^2) 因为随着 n 变得足够大,n^2 项变得比 n 大得多,以至于 n 项实际上是微不足道的。所以我们可以不考虑它。

              但是,这确实意味着大 O 表示法对于小 n 的用处不大,因为我们已经忘记的增长较慢的项仍然足以影响运行时。

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

              哦,我会使用它吗?是的,一直以来——当我弄清楚我的代码的效率时,它给出了一个很好的“粗略”的成本近似值。

              【讨论】:

                【解决方案8】:

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

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

                2) 像 'add' / 'sort' / 'remove' 这样的操作对于不同的数据结构(和算法)可能会花费不同的时间,例如对于 hashmap 来说,'add' 和 'find' 是 O(1) ,但对于二叉树来说是 O(log n)。处理普通数组时,QuickSort 的排序是 O(nlog n),而 BubbleSort 的排序是 O(n^2)。

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

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

                【讨论】:

                • 好的,它是什么,它如何应用于常见的数据结构,以及如何为自己的算法计算它?
                • 其他人已经回答过了。
                【解决方案9】:

                您应该能够评估算法的复杂性。这与了解它需要多少元素相结合可以帮助您确定它是否不适合其任务。

                【讨论】:

                  【解决方案10】:

                  来自维基百科.....

                  在分析算法以提高效率时,大 O 表示法很有用。例如,完成一个大小为 n 的问题所需的时间(或步骤数)可能被发现为 T(n) = 4n² - 2n + 2。

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

                  显然我从未使用过它..

                  【讨论】:

                    【解决方案11】:

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

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

                    假设列表中有 n 个项目。在最坏的情况下,您需要进行 n 次迭代。在大 O 表示中,它是 O(n)。

                    它实际上说明了算法的效率。

                    【讨论】:

                    • 这是错误的恕我直言。 Big-O 通常表示复杂度类。为了清楚起见,必须添加最坏情况、平均情况或最佳情况。
                    • 此外,Big-O 只是说算法的成本不比给定函数差,它没有说明这个界限有多紧密。
                    【解决方案12】:

                    Big-O for Eight Year Olds? 已经提出了一个非常相似的问题。希望那里的答案能回答您的问题,尽管那里的提问者确实对这一切都有一些数学知识,如果您需要更全面的解释,您可能没有那么清楚。

                    【讨论】:

                      猜你喜欢
                      • 2011-03-10
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-04-13
                      • 1970-01-01
                      • 2014-02-12
                      • 2020-09-12
                      • 2011-03-23
                      • 1970-01-01
                      相关资源
                      最近更新 更多