C 确定特定函数的时间复杂度
这是我最近遇到的一个关于算法和数据结构的旧考试中的一个问题。我很难理解这个解决方案。 我需要找到函数的C 确定特定函数的时间复杂度,c,time-complexity,C,Time Complexity,这是我最近遇到的一个关于算法和数据结构的旧考试中的一个问题。我很难理解这个解决方案。 我需要找到函数的big-O、big-ϴ和big-Ω边界: void recursion(int n) { int i; if (n == 0) { return; } for (i = 0; i < n; i++) { recursion(i); } } void递归(int n){ int i; 如果(n==0){ 返回; } 对于(i=0;i0,给定递归的迭代实现,因此可以归纳地证明T
big-O
、big-ϴ
和big-Ω
边界:
void recursion(int n) {
int i;
if (n == 0) {
return;
}
for (i = 0; i < n; i++) {
recursion(i);
}
}
void递归(int n){
int i;
如果(n==0){
返回;
}
对于(i=0;i
这三个问题的解决方案都是
2^n
,我不明白为什么。我试着把事情写下来,但我甚至无法接近解决方案。如果有人能解释一下2^n
从何而来,我将不胜感激。因为这闻起来像是一个家庭作业问题,这个答案是不完整的
这类问题背后的惯用伎俩是建立一个递推方程。也就是说,递归(k+1)
的时间复杂度在某种程度上与递归(k)
的复杂度有关。仅仅写下重复性本身不足以证明复杂性,你必须证明为什么重复性是真实的。但是,对于2n,这表明递归(k+1)
所花费的时间是递归(k)
的两倍
设T(k)表示递归(k)
的时间复杂度。因为递归(0)立即返回,所以让T(0)=1。对于k>0,给定递归的迭代实现,因此可以归纳地证明T(k)=2k
让我们将总运行时间表示为
f(n)
。由于函数中的循环,f(n)
实际上是i
的f(i)
之和,介于0和n-1之间。这是n
项的总和。让我们试着简化这个表达式。在这种情况下,一个标准的技巧是找到一个互补的等式。让我们看看f(n-1)
的值是多少。与前一种情况类似,对于i
,它是介于0和n-2之间的f(i)
之和。现在我们有两个方程:
f(n)=f(1)+...+f(n-1)
f(n-1)=f(1)+...+f(n-2)
让我们从第一个减去第二个:
f(n)-f(n-1)=f(n-1)
--> f(n)=2f(n-1)
现在这是一个很好的例子。
解决方案是即时的(有关更多详细信息,请参阅链接):
f(n)=f(1)*2n=2n让我们看看一个更简单的递归,它被称为O(2^n) 有8(2^3)个递归调用,因为每个n>2的调用会产生两个以上的递归调用,所以fib(n+1)的递归调用数是fib(n)的两倍 以你为例:
n = 3
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
当n=3时,我们得到7个递归调用
对于n=4
n = 4
n = 3
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
n = 2
n = 1
n = 0
n = 0
n = 1
n = 0
n = 0
这里,我们有15个电话。查看上面的执行树,您可以看到递归(4)基本上是递归(3)+递归(3)+1
所以一般来说,递归(n+1)比2*递归(n)多一个递归调用,2*递归(n)基本上是每+1到n增加一倍,这是O(2^n)
所以
因此=>
2^(n-1) * (n - (n-1))
那就是
2^n calls...
也许观察调用
递归(2)
和递归(3)
之间的差异会对你有所帮助。递归在这里不是无界的吗?@information\u interchange:No。调用递归(n)
中的每个递归调用都传递了一个小于n
的参数。啊,是的,我现在明白了;Fibonacci的朴素递归计算不是Φ(2^n)。是Φ(ψ^n),其中ψ是(sqrt(5)+1)/2,约为1.618。换句话说,它是Φ(fib(n)),这在递归本身中是清楚的。OP的递归实际上是Φ(2^n),但您的答案忽略了这一事实的简单证明。
n = 4
n = 3 // + 1
n = 2 //
n = 1 //
n = 0 // recursion(3)
n = 0 //
n = 1 //
n = 0 //
n = 0 //
n = 2 //
n = 1 //
n = 0 // recursion(3)
n = 0 //
n = 1 //
n = 0 //
n = 0 //
r(n) = r(n-1)+r(n-2)+...+r(0) // n calls.
r(n-1) = r(n-2)+r(n-3)+...+r(0) // n-1 calls.
r(n-2) = r(n-3)+r(n-4)+...+r(0) // n-2 calls.
.
.
.
r(1) = r(0) // 1 call.
r(0) = return; // 0 call.
r(n) = r(n-1)+r(n-2)+...+r(0) // n calls.
= 2 * (r(n-2)+...+r(0)) // 2 * (n - 1) calls.
= 2 * ( 2 * (r(n-3)+...+r(0)) ) // 2 * 2 * (n - 2) calls.
.
.
.
2^(n-1) * (n - (n-1))
2^n calls...