也许我对Big-O符号的理解是错误的(自从我开始学习算法以来已经有一段时间了),但以下对我来说从来没有太多意义:
这将被视为O(n ^ 2):
for (int i = 0; i < num_1; i++)
{
for (int j = 0; j < num_2; j++)
{
cout << i << " " << j << endl;
}
}
这将被视为O(n):
for (int z = 0; z < num_3; z++) { cout << z << endl; }
我的问题是实际用语。让我们假设num_1 = 10; num_2 = 20; num_3 = 1000;
。在这种情况下,第一个例子是O(n ^ 2),它的内部迭代次数比O(n)第二个例子少得多。
用更一般的术语来说:当num_3 > num_1 * num_2
时,O(n ^ 2)片段的作用小于O(n)片段。在实际应用程序中,这两个片段可能正在执行两个非常独立的任务,其中num_1
,num_2
和num_3
上的功能界限有很大差异。嵌套的num_1
和num_2
可能在0到255之间循环变量值,但num_3
可能会超过一百万的频繁值。
为什么编码人员在没有考虑实际或操作变量边界时,是否应该基于其Big-O表示法信任算法或片段?
答案 0 :(得分:4)
如果明确知道应该是什么,那么O(n^2)
中的某些内容才有意义。通常它指的是输入的大小(或者如果输入是一个数字,它只是指那个数字),但在你的代码中,它不清楚输入是什么。
for (int i = 0; i < num_1; i++)
{
for (int j = 0; j < num_2; j++)
{
cout << i << " " << j << endl;
}
}
通常可以说上述代码段的运行时间在O(num_1 * num_2)
。如果num_1
和num_2
都是常量,则表示它位于O(1)
中。如果num_1
和num_2
都与程序输入(n
)的大小成线性比例,那么它确实是O(n^2)
。如果num_1
和num_2
都与输入大小的平方成正比,则它位于O(n^4)
。
底线:它完全取决于num_1
和num_2
是什么以及如何以及取决于他们成长的因素。
for (int z = 0; z < num_3; z++) { cout << z << endl; }
现在此代码位于O(num_3)
。根据{{1}}说出这是什么意味着再次要求我们知道n
与num_3
的关系。
如果n
,num_1
和num_2
的所有内容与num_3
呈线性比例,那么您确实可以说第一个代码段在n
时间内运行和O(n^2)
中的第二个。但是,在这种情况下,对于足够大的O(n)
,num_3
无法大于num_1 * num_2
。
答案 1 :(得分:3)
Big O描述算法速度,而不是实际代码。
当你有一个通用算法时,你不知道变量的约束是什么。
答案 2 :(得分:0)
大哦符号是一种将计算复杂性表示为增长率函数的方法。绝对必须要理解的是,它是一个近似值,并且实际上只能忽略所涉及的变量的大值(例如N)。
绝对正确的是,单个变量值,常量等会产生很大影响。
然而,对于类似(和大)大小的变量值,一组算法的big-Oh表达式将指示它们的相对性能。更典型的是,它是一种方便的实现独立方式,用于表示算法的最佳,平均和最差情况复杂性。
但是,在一天结束时,一旦选择了候选算法的简短列表(可能基于大哦符号,以及其他特征,例如空间要求等),那么使用代表性数据集计时实施是要走的路。
答案 3 :(得分:0)
Big O符号表示算法对给定幅度的数据有多长时间工作,以及当获得更多数据时它将如何“缩放”,如果O(n)算法获得的数据多于O(n ^ 2)算法(正如你在你的例子中所示)。但是如果你向O(n)算法提供2倍以上的数据,你应该期望运行时间延长2倍,而O(n ^ 2)你应该期望长4倍。
答案 4 :(得分:0)
你可以将这些例子中的Big O想象为N接近无穷大。
所以你在你的场景中就是num_3&gt; num_1 * num_2,但随着这三个数字越来越大,它将不再成立。
如果algorithm1是O(N)且算法2是O(N ^ 2),它并不意味着algorithm1总是比算法2好,它只是意味着N有一些阈值(通常称为N0),之后point algorithm1的性能优于algorithm2。
一个随机的例子是插入排序是O(N ^ 2),其中MergeSort是O(N * log(N)),但是对于非常小的N值,插入排序实际上最终会更快。一旦N变得足够大,MergeSort总是更快。 Arrays.sort
函数的Java版本实际上有一个if
语句,它对非常小的N值使用插入排序,对大于特定大小的任何东西使用修改的快速排序或合并排序(幻数是约N = 7)。
Arrays.sort
数组的int
的Java代码(在Java 6中)如下所示:
private static void sort1(int x[], int off, int len) {
// Insertion sort on smallest arrays
if (len < 7) {
//insertion sort
}
//modified quick sort
}
在一天结束时,Big O符号是一种分类机制,可帮助您快速分析&amp;以独立于计算机硬件的方式比较算法,并且不需要您编写,测试和计算各种算法的执行时间。这是一个简化的符号,所以它永远不会是精确的,正如我刚给出的示例所示,它非常依赖于数据的大小和范围。
算法的Big O表示法的一个主要警告是,如果您可以对数据做出假设,通常可以对算法进行改进。
答案 5 :(得分:0)
Big-O为您提供上限或最差情况下的增长率。常量被忽略,因为随着n的增长,它们变得越来越无关紧要(例如,而不是说O(3 + 2n),你只会说O(n))。
Big-Omega是一个最佳案例增长率,根据您对算法使用方式的了解,您可能更适合在某些情况下使用。
如果给定算法的Big-O和Big-Omega相同,则称为精确顺序,您可以将其称为Big-Theta。
编辑:为了澄清,最坏情况分析通常更可取,因为您希望能够告诉客户“它将始终表现良好或更好”,而不是“如果您的数据恰好是完美的,它将表现出色! “