递归法把问题转化为规模更小的子问题解决。
递归法思路清子晰,编程简单,但有时候难以想到。
如果确定了用递归法解题,思考的重点应放到建立原问题和子问题之间的联系。
有的问题有很明显的递归结构,但需要仔细思考,才能转化为相同的子问题。
边界条件与递归方程是递归函数的两个要素,递归函数只有具备了这两个要素,才能在有限次计算后得出结果。
斐波那契数列
我们知道斐波那契数列的前面几项,1、1、2、3…,和斐波那契数列的递推公式为
F[i] = F[i-1] + F[i-2]
现在给出一个n,计算出F[n]的值。
#include<stdio.h>
#include<time.h>
int num=0;
int F(int a)
{
num++;
if(a==0 || a==1)
return 1;
else
return F(a-1)+F(a-2);
}
int main()
{
long op,ed;
int n;
while(scanf(“%d”,&n)!=EOF)
{
num=0;
op=clock();
printf(“F(%d) = %d\n”,n,F(n));
printf(“递归次数:%d\n”,num);
ed=clock();
printf(“时间:%ldms\n”,ed-op);
}
return 0;
}
1
F(1) = 1
递归次数:1
时间:1ms
2
F(2) = 2
递归次数:3
时间:1ms
4
F(4) = 5
递归次数:9
时间:2ms
30
F(30) = 1346269
递归次数:2692537
时间:16ms
40
F(40) = 165580141
递归次数:331160281
时间:1078ms
实现递归所帘的空间量与递归树的高度直接成正比.程序的时间需求与所完成的函数次数有关,
因此与树中的顶点总数有关,但空间需求仅是从单个顶点反向回到根的路径上的那些存储
区,因此树的高度反映了空间需求. 一棵很均匀的、浓密的递归树意味着以较少的额外空间
需求做大量工作的递归过程.
优化: 我们发现之所以慢的原因是计算了其实是多了很多的重复计算造成的,例如在计算完 F[5] 的时候,F[3],F[4],已经计算出来了,而计算F[5]的时候确把F[3],F[4],F[5]又计算了一遍,那么我们只要把之前得出的结果保存一下,在用的时候直接调用即可。
#include<stdio.h>
#include<time.h>
int f[100];
int num;
int F(int a)
{
num++;
if(f[a])
return f[a];
if(a==1 || a==2)
return 1;
else
return f[a]=F(a-1)+F(a-2);
}
int main()
{
long op,ed;
int n;
while(scanf(“%d”,&n)!=EOF)
{
num=0;
op=clock();
printf(“F(%d) = %d\n”,n,F(n));
printf(“递归次数:%d\n”,num);
ed=clock();
printf(“时间:%ldms\n”,ed-op);
}
return 0;
}
1
F(1) = 1
递归次数:1
时间:2ms
2
F(2) = 1
递归次数:1
时间:2ms
4
F(4) = 3
递归次数:3
时间:2ms
30
F(30) = 832040
递归次数:53
时间:7ms
40
F(40) = 102334155
递归次数:21
时间:6ms
非递归:
#include<stdio.h>
#include<time.h>
int main()
{
long op,ed;
int n,i;
int F[1000]={1,1};
while(scanf(“%d”,&n)!=EOF)
{
op=clock();
for(i=2;i<=n;i++)
F[i]=F[i-1]+F[i-2];
ed=clock();
printf(“F(%d) = %d\n”,n,F[n]);
printf(“时间:%ldms\n”,ed-op);
}
return 0;
}
5
F(5) = 8
时间:0ms
10
F(10) = 89
时间:0ms
20
F(20) = 10946
时间:0ms
30
F(30) = 1346269
时间:0ms
40
F(40) = 165580141
时间:0ms
迭代:
#include<stdio.h>
#include<time.h>
int fibonacci(int n)
{
int last_but;
int last;
int current;
int i;
if(n<=0)
return 0;
else if(n==1)
return 1;
else
{
last_but=0;
last=1;
for(i=2;i<=n;i++)
{
current=last_but+last;
last_but=last;
last=current;
}
return current;
}
}
int main()
{
int a;
long op,ed;
while(scanf(“%d”,&a)!=EOF)
{
op=clock();
printf(“F(%d) = %d\n”,a,fibonacci(a));
ed=clock();
printf(“时间为:%ldsm\n”,ed-op);
}
return 0;
}
2
F(2) = 1
时间为:1sm
4
F(4) = 3
时间为:0sm
30
F(30) = 832040
时间为:0sm
40
F(40) = 102334155
时间为:1sm
这个迭代函数所用的时间显然是按n 成线性增长(即直接正比子n) I 因此这个函数的时
间与递归函数的指数级时间的差异是巨大的。
阶乘
递归
#include<stdio.h>
#include<time.h>
int N(int a)
{
if(a==0)
return 1;
else
return a*N(a-1);
}
int main()
{
long op,ed;
int n;
while(scanf(“%d”,&n)!=EOF)
{
op=clock();
printf(“%d的阶乘为%d\n”,n,N(n));
ed=clock();
printf(“递归时间为:%ldsm\n”,ed-op);
}
return 0;
}
非递归
#include<stdio.h>
#include<time.h>
int main()
{
long op,ed;
int n,i;
while(scanf(“%d”,&n)!=EOF)
{
int sum=1;
op=clock();
for(i=1;i<=n;i++)
{
sum=sum*i;
}
printf(“%d的阶乘为%d\n”,n,sum);
ed=clock();
printf(“递归时间为:%ldsm\n”,ed-op);
}
return 0;
}