Big-O 复杂度递归与迭代
Big-O complexity recursion Vs iteration
Determining complexity for recursive functions (Big O notation) 上的问题 5 是:
int recursiveFun(int n)
{
for(i=0; i<n; i+=2)
// Do something.
if (n <= 0)
return 1;
else
return 1 + recursiveFun(n-5);
}
为了突出我的问题,我将递归参数从 n-5
更改为 n-2
:
int recursiveFun(int n)
{
for(i=0; i<n; i+=2)
// Do something.
if (n <= 0)
return 1;
else
return 1 + recursiveFun(n-2);
}
我理解循环在 n/2
中运行,因为标准循环在 n
中运行并且我们迭代了一半的次数。
但是递归调用不也是这样吗?对于每个递归调用,n
减 2。如果 n
为 10,则调用堆栈为:
recursiveFun(8)
recursiveFun(6)
recursiveFun(4)
recursiveFun(2)
recursiveFun(0)
...这是 5 个调用(即 10/2
或 n/2
)。然而 Michael_19 提供的答案表明它在 n-5
中运行,或者在我的示例中,n-2
。显然 n/2
与 n-2
不同。我哪里出错了,为什么在分析 Big-O 时 递归 与 迭代 不同?
分析递归算法的big-O的常用方法是找到一个递归公式"counts"算法完成的操作数。通常表示为T(n)
.
在你的例子中:这段代码的时间复杂度可以用公式来描述:
T(n) = C*n/2 + T(n-2)
^ ^
assuming "do something is constant Recursive call
因为很明显它将在 O(n^2)
中,让我们使用归纳法来显示 Omega(n^2)
:
归纳假设:
T(k) >= C/8 *k^2 for 0 <= k < n
确实:
T(n) = C*n/2 + T(n-2) >= (i.h.) C*n/2 + C*(n-2)^2 / 8
= C* n/2 + C/8(n^2 - 4n + 2) =
= C/8 (4n + n^2 - 4n + 2) =
= C/8 *(n^2 + 2)
确实:
T(n) >= C/8 * (n^2 + 2) > C/8 * n^2
因此,T(n)
在 big-Omega(n^2)
中。
显示大 O 的方法类似:
假设:T(k) <= C*k^2
对于所有 2 <= k < n
T(n) = C*n/2 + T(n-2) <= (i.h.) C*n/2 + C*(n^2 - 4n + 4)
= C* (2n + n^2 - 4n + 4) = C (n^2 -2n + 4)
对于所有 n >= 2
、-2n + 4 <= 0
,因此对于任何 n>=2
:
T(n) <= C (n^2 - 2n + 4) <= C^n^2
假设是正确的 - 根据 big-O 的定义,T(n) 在 O(n^2) 中。
因为我们已经证明 T(n) 既在 O(n^2) 和 Omega(n^2) 中,它也在 Theta(n^2)
中
分析递归不同于分析迭代,因为:
n
(和其他局部变量)每次都会改变,可能很难捕捉到这种行为。
- 当有多个递归调用时,事情会变得更加复杂。
Determining complexity for recursive functions (Big O notation) 上的问题 5 是:
int recursiveFun(int n)
{
for(i=0; i<n; i+=2)
// Do something.
if (n <= 0)
return 1;
else
return 1 + recursiveFun(n-5);
}
为了突出我的问题,我将递归参数从 n-5
更改为 n-2
:
int recursiveFun(int n)
{
for(i=0; i<n; i+=2)
// Do something.
if (n <= 0)
return 1;
else
return 1 + recursiveFun(n-2);
}
我理解循环在 n/2
中运行,因为标准循环在 n
中运行并且我们迭代了一半的次数。
但是递归调用不也是这样吗?对于每个递归调用,n
减 2。如果 n
为 10,则调用堆栈为:
recursiveFun(8)
recursiveFun(6)
recursiveFun(4)
recursiveFun(2)
recursiveFun(0)
...这是 5 个调用(即 10/2
或 n/2
)。然而 Michael_19 提供的答案表明它在 n-5
中运行,或者在我的示例中,n-2
。显然 n/2
与 n-2
不同。我哪里出错了,为什么在分析 Big-O 时 递归 与 迭代 不同?
分析递归算法的big-O的常用方法是找到一个递归公式"counts"算法完成的操作数。通常表示为T(n)
.
在你的例子中:这段代码的时间复杂度可以用公式来描述:
T(n) = C*n/2 + T(n-2)
^ ^
assuming "do something is constant Recursive call
因为很明显它将在 O(n^2)
中,让我们使用归纳法来显示 Omega(n^2)
:
归纳假设:
T(k) >= C/8 *k^2 for 0 <= k < n
确实:
T(n) = C*n/2 + T(n-2) >= (i.h.) C*n/2 + C*(n-2)^2 / 8
= C* n/2 + C/8(n^2 - 4n + 2) =
= C/8 (4n + n^2 - 4n + 2) =
= C/8 *(n^2 + 2)
确实:
T(n) >= C/8 * (n^2 + 2) > C/8 * n^2
因此,T(n)
在 big-Omega(n^2)
中。
显示大 O 的方法类似:
假设:T(k) <= C*k^2
对于所有 2 <= k < n
T(n) = C*n/2 + T(n-2) <= (i.h.) C*n/2 + C*(n^2 - 4n + 4)
= C* (2n + n^2 - 4n + 4) = C (n^2 -2n + 4)
对于所有 n >= 2
、-2n + 4 <= 0
,因此对于任何 n>=2
:
T(n) <= C (n^2 - 2n + 4) <= C^n^2
假设是正确的 - 根据 big-O 的定义,T(n) 在 O(n^2) 中。
因为我们已经证明 T(n) 既在 O(n^2) 和 Omega(n^2) 中,它也在 Theta(n^2)
分析递归不同于分析迭代,因为:
n
(和其他局部变量)每次都会改变,可能很难捕捉到这种行为。- 当有多个递归调用时,事情会变得更加复杂。