调试并运行下面这段代码,会发现它无法得到n!的正确结果,请分析为什么会产生这样的结果?对此程序代码,只允许修改一条语句,将其改正,功能要求实现n!。
auto改为static
将return p修改为return p*Func(n-1);实现递归调用就可以了。
斐波那契数列:1 1 2 3 5 8 13 21 34 55...
规律:第n个数字等于n前两个数字之和
Fib(n) = 1, n <= 2
Fib(n) = Fib(n - 1) + Fib(n - 2), n <= 2
递归思路:
#include <stdio.h>
int Fib(int a)
{
if (a > 2)
return Fib(a - 1) + Fib(a - 2);
else
return 1;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
无减枝操作的斐波那契递归代码效率很低下,如果参数比较大,那就会报错: stack overflow(栈溢出) 这样的信息。
系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一 直开辟栈空间,最终产生栈空间耗尽的情况,即栈溢出。
那如何解决上述的问题:
1. 将递归改写成非递归。
2. 使用static对象替代 nonstatic 局部对象。
在递归函数设计中,可以使用 static 对象替代 nonstatic 局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放 nonstatic 对象的开销,而且 static 对象还可以保 存递归调用的中间状态,并且可为 各个调用层所访问。
非递归版本:
第一次:
a = 1,b = 1,c = a + b
第二次:
a = b,b = c,c = a + b
所以非递归代码为:
//更简洁的代码
#include <stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while(n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
//初始构思的代码
#include <stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
int i = 0;
if (n <= 2)
return 1;
for (i = 0; i < n - 2; i++) //因为逻辑上当n > 2时,才开始循环,所以n=3对应第1次循环 所以
//判断条件为i < n - 2
{
a = b;
b = c;
c = a + b;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
小结:
1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。