我遇到了一些大问题的挑战。这些不是家庭作业问题。我正在写这些问题,以便更好地理解这里的概念。
function func(n)
{
int k,i = 0;
while(k < n){ < --- Guessing this outer loop is O(n/2)
k = n + 2
i = 0;
while(i < k){ <--- Not sure what this is?
i ++;
i = i * i;
}
}
}
如果你能向我解释内循环中发生了什么,以及你的逻辑最终会以最终结束的最大符号结束,我真的很喜欢它。
答案 0 :(得分:4)
外部循环及其测试(k < n)
及其步骤k = n + 2
将运行一次,提供O(1)因子的复杂性。
内部循环有测试(i < k)
,也就是(i < n+2)
,并且步骤i++; i=i*i;
最后,
i = (...(((1+1)^2+1)^2+1)^2+ ... )^2 > n+2`
使i
的值超指数。也就是说,i
在p遍中比exp(exp(p))增长得更快,因此总体复杂度小于O(log log n)。这比前面提到的O(log n)更严格,它也是一个上限,但不是那么紧。
答案 1 :(得分:2)
第二个循环将i
的值平方,直到达到k
。如果我们忽略常量项,则此循环在O(log k)
时间内运行。
为什么?因为如果您解决i^m = k
,则会获得m = constant * log(k)
。
正如你所说,外循环在O(n)
时间运行。
由于k
的较大值取决于n
,您可以说内部循环在O(log n)
中运行,这使您的整体复杂度为O(n log n)
。
答案 2 :(得分:2)
虽然@alestanis提供的内容对我而言比对评论中的那些更多准确分析这个问题,但我仍然认为这不是正确的。
让我们创建一个小的测试程序,打印出内循环产生的i
的值:
#include <iostream>
void inner(double k) {
double i;
i = 0.0;
while(i < k) {
i ++;
i = i * i;
std::cout << i << "\n";
}
}
int main() {
inner(1e200);
return 0;
}
当我运行时,我得到的结果是:
1
4
25
676
458329
2.10066e+011
4.41279e+022
1.94727e+045
3.79186e+090
1.43782e+181
1.#INF
如果迭代次数是对数的,那么达到特定数字的迭代次数应该与限制中的位数成比例。例如,如果它是对数的,它应该需要大约180次迭代才能达到1e181,给出或取一些(相当小的)常数因子。这显然不是这里的情况 - 通过用科学记数法查看结果的指数很容易看出,这大约是每次迭代的位数加倍,其中对数意味着每次迭代大致增加一位数。
我不是绝对肯定,但我相信将内循环放在O(log log N)而不仅仅是O(log N)。我认为很容易同意外部循环可能是O(N)(尽管它目前只执行一次),整体复杂度为O(N log log N)
。
我觉得有必要从务实的角度来看,O(log log N)
通常可以被视为基本上不变 - 如上所示,只能通过典型的双精度浮点数指定的最高限制11次迭代。因此,对于大多数实际目的,整体复杂性可以视为O(N)
。