函数递归
什么是递归?
是指函数/过程/子程序在运行过程中直接或间接调用自身而产生的重入现象。(百度百科)
分析这句话,函数自己调用自己,就是函数递归。
字面意义我们有所了解,接下来看一下实例分析:
实例:斐波那契数列
什么是斐波那契数列?(百度百科)
斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597…
用通俗的话来进行定义,该数列从第三项开始,每一项都等于前两项之和。
我们来做一个程序,要求输出斐波那契数列的第n项。
我们先按照定义把他运行出来:
#includ <stdio.h>
size_t Fib(int n)
{
int fib1=1;
int fib2=1;
int fib;
if (n <= 2) return 1;
for (int i = 3; i <= n; ++i)
{
fib = fib1 + fib2;
fib1 = fib2;
fib2 = fib;
}
return fib;
}
void main()
{
int n=8;
size_t result = Fib(n);
printf("result=%u\n",result);
我们得到的输出结果是这样的:
第八项的数字是21,程序正常运行
那么我们如何用递归的方式来输出斐波那契数列的第n项呢?
首先我们来设想一下,我们知道,数列的前两项都为1,从第三项开始,每一项都等于前两项之和。那么我们是不是可以做出一个像下面的这个分段函数呢?
通过递归的方式,并不难以实现。接下来我们设计程序来运行它:
#includ <stdio.h>
size_t Fib(int n) //主函数
{
if (n<=2)
return 1;
else
return Fib(n - 1) + Fib(n - 2); //在函数内部调用自己(递归)
}
void main()
{
int n =8;
size_t result = Fib(n);
printf("\nresult=%u\n", result);
}
运行结果如下:
程序仍然照常运行。
-两种程序的意义相同,但从二者代码的文面来看,利用函数递归明显意思更为清晰,容易理解,最重要的是更加方便。
但要是n=80呢?
我们用两种程序分别运行一下:
第①种:
程序立马运行出了第80项的值为4009959909
第②种:
我们可以看到,光标在不停的闪烁。 过了很久才会输出我们想要的第80项的值。这是为什么呢?
其原因在于,每一次递归,都会将临时变量暂存在计算机开辟的栈中。当数值特别大时,占用的空间特别大,计算机开辟空间也需要时间,程序运行出来就需要很长的时间。
而非递归不需要栈的开辟,直接运行,速度很快。
由此,递归的 两个必要条件 就显得十分重要。
- 存在限制条件,当满足这个限制条件的时候,递归就不再继续。
- 每次递归调用之后越来越接近这个限制的条件。
一般而言,我们不希望限制条件过大。
引申–青蛙跳台阶问题
题目
一只青蛙一次可以跳上1级台阶,也可以跳2级。求该青蛙跳上一个n级台阶总共有多少种跳法。(先后次序不同算不同的结果)
分析
当n = 1, 只有1中跳法;当n = 2时,有两种跳法;当n = 3 时,有3种跳法;当n = 4时,有5种跳法;当n = 5时,有8种跳法…
1,2,5,8…,我们可以发现,从第二项开始,每一项等于前两项之和,这不就是斐波那契数列吗?
我们设计与之类似的函数,很容易计算出青蛙跳n级台阶的方法数。
#include <stdio.h>
size_t TaiJie(int n)
{
if (n<=2)
return 1;
else
return TaiJie(n - 1) + TaiJie(n - 2);
}
void main()
{
int n =9;
size_t result = TaiJie(n);
printf("\nresult=%u\n", result);
}
运行结果不再展示。