1、递归的概念
递归是一个函数在内部自己调用这个函数自身。
【例1】求1+2+……+n的和
//求1+2+···+n的和
#include<stdio.h>
#include<stdlib.h>
//方法一:用递归算法实现
int AddN(int n)
{
return (n <=0) ? 0 : n + AddN(n - 1);
}
//方法二:用循环实现
int AddN1(int n)
{
int result = 0;
for (int i = 1; i <= n; i++)
{
result += i;
}
return result;
}
int main()
{
int ret = AddN(3);
int ret1 = AddN1(3);
printf("%d\n", ret);
printf("%d\n", ret1);
system(“pause”);
return 0;
}
运行结果:
2、递归的优点
递归的代码比较简洁。递归的本质是把一个问题分成两个或者多个小问题。
【例2】求n的阶乘
//求一个数的阶层
#include<stdio.h>
#include<stdlib.h>
//方法一:循环
long long MutexN(unsigned int n)
{
long long result = 1;
for (int i = 1; i <= n; i++)
{
result = result * i;
}
return result;
}
//方法二:递归
long long MutexN1(unsigned int n)
{
return (n > 1) ? n * MutexN(n - 1) : 1;
}
int main()
{
long long ret = MutexN(3);
long long ret1 = MutexN1(3);
printf("%d\n", ret);
printf("%d\n", ret1);
system(“pause”);
return 0;
}
运行结果:
3、递归的缺点
递归由于是函数在内部调用自身,而函数的调用是有时间和空间消耗的:
(1)函数要在栈上开辟空间以保存局部变量、函数参数和返回值.
(2)往栈里压入数据和弹出数据都需要消耗时间。
(3)调用栈溢出问题:每一次函数调用都需要在内存中分配空间,而每个进程的栈容量是有限的,当递归调用的层级太多时,就会超出栈容量,从而导致栈溢出。
【例3】求斐波那契数列的第n项。
//斐波那契数列
#include<stdio.h>
#include<stdlib.h>
//方法一:递归
long long Fibonacci(unsigned int n)
{
if (n == 0)
{
return 0;
}
else if(n == 1)
{
return 1;
}
else
{
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
}
//方法二:循环
long long Fibonacci1(unsigned int n)
{
if (n == 0)
{
return 0;
}
if (n == 1)
{
return 1;
}
long long head = 1;
long long behind = 0;
long long addn = 0;
for (int i = 2; i <= n; i++)
{
addn = head + behind;
behind = head;
head = addn;
}
return addn;
}
int main()
{
long long ret = Fibonacci(2);
long long ret1 = Fibonacci1(2);
printf("%d\n", ret);
printf("%d\n", ret1);
system(“pause”);
return 0;
}
运行结果为:
注意:递归是从上往下计算,而循环是从下往上计算。
4、斐波那契数列的应用
(1)青蛙跳台阶问题
一直青蛙一次可以跳上1阶台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法?
分析:
1)首先考虑最简单的情况。如果只有1级台阶,那显然只有一种跳法。如果有2级台阶,那就有2种跳法:一种是分2次跳,每次跳1级;另外一种是一次跳2级。
2)考虑一般情况。把n级台阶时的跳法看成n的函数,记为f(n)。当n>2时,第一次跳的时候就有2种不同的选择:一是第一次跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);二是第一次跳2级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-2)。因此,n级台阶的不同跳法的总数f(n)=f(n-1)+f(n-2)。
(2)小矩形覆盖大矩形问题
用21的小矩形横着或者竖着去覆盖大矩形。请问,用8个21的小矩形无重叠地覆盖一个28的大矩形,总共有多少种方法?
分析:
先把28的覆盖方法记为f(8)。用第一个21的小矩形去覆盖大矩形的最左边时有两种选择:竖着放或者横着放。当竖着放的时候,右边还剩下27的区域,这种情形下的覆盖方法记为f(7)。接下来考虑横着放的情况。当21的小矩形横着放在左上角的时候,左下角必须也横着放一个21的小矩形,而在右边还剩下2*6的区域,这种情形下的覆盖方法记为f(6),因此f(8)=f(7)+f(6)。此时可以看出,这是一个斐波那契数列。