我们今天在课堂上做了一个关于大O符号的练习。这是其中一个问题:
void modifyArray(int a[], int size)
{
int max = a[0];
for (int i = 1; i < size / 2; ++i)
{
if (max < a[i])
max = a[i];
}
for (int j = 1; j <= size * size; ++j)
{
++max;
cout << max;
}
}
我的直觉告诉我f(n)= n / 2 + n 2 = O(n 2 )但根据我的教授,答案就是O( N)。任何人都可以向我解释为什么以及何时我们只是改变我们认为的输入大小?
我知道它不是一个嵌套循环 - 这不是让我感到困惑的东西。我不明白为什么对于给定的输入size
,第二个循环只被认为是O(n)。我能理解这一点的唯一方法是,如果我们隔离第二个循环,然后将输入大小重新定义为n = size ^ 2。我是在正确的轨道上吗?
答案 0 :(得分:4)
如果您提供的代码完全是您的教授正在评论的代码,那么(<)他错误。如上所述,它将每个数字从1输出到size * size
,这绝对是O(n ^ 2),因为n = size是理智的选择。
是的,你认为你可以说“O(n),其中n是数组大小的平方”,这是正确的,但这是没有目的的并发症。
正如其他人所说,如果cout << max
被删除,编译器可以将循环优化为单个O(1)赋值,这意味着函数的其他O(n)运算决定整体的大O效率,但可能不 - 谁说你甚至可以实现优化?因此,描述大O效率的最佳方式是“如果优化在O(n)中进行其他O(n ^ 2)” - 断言一个或另一个然后隐藏您的假设是没有用的,并且如果他们错了,会在脚注中产生后果。
答案 1 :(得分:3)
考虑这个例子:
for (i = 0; i < N; i++) {
sequence of statements
}
for (j = 0; j < M; j++) {
sequence of statements
}
第一个循环是O(N),第二个循环是O(M)。既然你不知道哪个更大,你说这是O(max(N,M))。
在您的情况下,N = size / 2,M = size * size。
O(max(N,M))变为O(max(尺寸/ 2,尺寸*尺寸)),其为O(尺寸*尺寸)。 所以f(n)= O(size ^ 2)= O(n ^ 2)
你问的问题; 是的,我认为,你认为是正确的。 将输入大小重新定义为n = size ^ 2. 这应该是将其视为O(n)的方式。
答案 2 :(得分:1)
实际上第二个循环可以完成。
如果您不考虑输出中间词,那么
It is equivalent to max += size*size.
然后代码复杂度将减少到O(size/2) ~ O(size)
。