这里的关键是可视化调用树。一旦这样做了,复杂性是:
nodes of the call tree * complexity of other code in the function
后一项的计算方法与我们计算普通迭代函数的方法相同。
相反,完整树的总节点计算为
C^L - 1
------- , when C>1
/ C - 1
/
# of nodes =
\
\
L , when C=1 (this is special case of a single branch tree)
其中C是每个节点的子节点数,L是树的层数(包括根)。
这棵树很容易形象化。从第一个调用(根节点)开始,然后绘制与函数中递归调用数量相同的子节点数。将传递给子调用的参数写成“节点的值”也是有用的。
下面是上面例子的结果:
int recursiveFun1(int n)
{
if (n <= 0)
return 1;
else
return 1 + recursiveFun1(n-1);
}
首先考虑调用树:
N级别1
N-1 level 2
N-2 level 3
N-3等级4
... ~ n级-> L = n
这里每个节点的子节点数为C = 1,层数L = n+1。其余函数的复杂度为O(1)。因此总复杂度为L * O(1) = (n+1) * O(1) = O(n)
int recursiveFun2(int n)
{
if (n <= 0)
return 1;
else
return 1 + recursiveFun2(n-5);
}
这里的调用树是:
n
存在
n-10
c15
... ~ n/5级-> L = n/5
C = 1,但L = n/5。其余函数的复杂度为O(1)。因此总复杂度为L * O(1) = (n/5) * O(1) = O(n)
int recursiveFun3(int n)
{
if (n <= 0)
return 1;
else
return 1 + recursiveFun3(n/5);
}
调用树为:
n
n / 5
n / 5 ^ 2
n / 5 ^ 3
... ~ log5(n)级-> L = log5(n)
因此C = 1, L = log(n)。其余函数的复杂度为O(1)。因此,总复杂度为L * O(1) = log5(n) * O(1) = O(log(n))
void recursiveFun4(int n, int m, int o)
{
if (n <= 0)
{
printf("%d, %d\n",m, o);
}
else
{
recursiveFun4(n-1, m+1, o);
recursiveFun4(n-1, m, o+1);
}
}
这里,调用树更加复杂:
N级别1
N-1 N-1 level 2
N-2 N-2 N-2 N-2…
N-3 N-3 N-3 N-3 N-3 N-3 N-3 N-3 N-3…
…~ n级-> L = n
其中每个节点的子节点数为C = 2,而L = n。其余函数的复杂度为O(1)。
这一次我们使用调用树中节点数的完整公式,因为C > 1。因此总复杂性(C ^ l - 1) /(颈- 1)* O (1) = (2 ^ n - 1) * O (1) = O (2 ^ n)。
int recursiveFun5(int n)
{
for (i = 0; i < n; i += 2) {
// do something
}
if (n <= 0)
return 1;
else
return 1 + recursiveFun5(n-5);
}
同样,调用树是:
n
存在
n-10
c15
... ~ n/5级-> L = n/5
这里C = 1, L = n/5。其余函数的复杂度是O(n)因此,总复杂度为L * O(1) = (n/5) * O(n) = O(n²)