考虑下面的C函数。
unsigned fun(unsigned n)
{
if (n == 0) return 1;
if (n == 1) return 2;
return fun(n-1) + fun(n-1);
}
对于上面的代码,请考虑以下问题,而忽略编译器的优化。
a)上面的代码有什么作用?
b)以上代码的时间复杂度是多少?
c)可以降低上述函数的时间复杂度吗?
fun(n)有什么作用?
在上面的代码中,fun(n)等于2 * fun(n-1)。因此,上面的函数返回2 n 。例如,对于n = 3,它返回8;对于n = 4,它返回16。
fun(n)的时间复杂度是多少?
以上函数的时间复杂度是指数的。令时间复杂度为T(n)。 T(n)可以写成下面的递归。 C是机器相关的常数。
T(n) = T(n-1) + T(n-1) + C
= 2T(n-1) + C
上述重复的解为Θ(2 n )。我们可以通过递归树法解决它。递归树将是高度为n的二叉树,除最后一个级别外,每个级别都将完全填满。
C
/ \
C C
/ \ / \
C C C C
/ \ / \ / \ / \
. . . . . . . .
. . . . . . . .
Height of Tree is Θ(n)
可以减少fun(n)的时间复杂度吗?
减少时间复杂度的一种简单方法是拨打一个电话而不是2个电话。
unsigned fun(unsigned n)
{
if (n == 0) return 1;
if (n == 1) return 2;
return 2*fun(n-1);
}
上述解决方案的时间复杂度为Θ(n)。 T令时间复杂度为T(n)。 T(n)可以写成下面的递归。 C是机器相关的常数。
T(n) = T(n-1) + C
我们可以通过递归树法解决它。递归树将是高度为n的偏斜二叉树(每个内部节点只有一个孩子)。
C
/
C
/
C
/
.
.
Height of Tree is Θ(n)
可以使用分而治之技术来进一步优化上述函数,以计算功效。
unsigned fun(unsigned n)
{
if (n == 0) return 1;
if (n == 1) return 2;
unsigned x = fun(n/2);
return (n%2)? 2*x*x: x*x;
}
上述解决方案的时间复杂度为Θ(Logn)。令时间复杂度为T(n)。 T(n)可以近似地写成下面的递归。 C是机器相关的常数。
T(n) = T(n/2) + C
我们可以通过递归树法解决它。递归树将是高度为Log(n)的偏斜二叉树(每个内部节点只有一个子节点)。
C
/
C
/
C
/
.
.
Height of Tree is Θ(Logn)
我们还可以使用按位左移运算符'<
unsigned fun(unsigned n) { return 1 << n; } |