一、递归函数简介
1、递归概述
- 递归是解决问题的一种方法,它将问题不断分成更小的子问题,知道子问题可以用普通方法解决。同常情况下,递归会使用一个不停调用自己的函数,尽管表面上看起来很普通,但是递归可以帮助我们写出非常优雅的解决方案。对于某些问题,如果不用递归就很难解决。
2、递归特性
①递归本身是一个函数,需要函数定义方式描述
②函数内部,采用分支语句对输入参数进行判断
3、循环自身调用
def demo():
print('Python 真好玩')
demo()
demo()
- 上述代码中,创建了自定义函数demo(),函数内部不断调用自身,代码的执行结构为重复输出字符串’Python 真好玩’,输出次数不超过1000次,这是因为一个函数最多只能调用低级1000次,重复调用会导致栈内存溢出,那么demo()函数是递归函数吗?
4、递归函数三原则
-
正如科幻作家阿西莫夫提出的机器人三原则一样,一个自定义函数想成为递归函数必须要遵循以下三个原则:
①递归算法必须具有基本情况
②递归算法必须改变其状态像基本情况靠近
③递归算法必须以递归的方式调用自己 -
按照上述三种原则可以去对比一个函数是否为递归函数,像前面所述demo()函数并没有基本情况,只是进行了调用自己,因此不属于递归函数。
二、递归求阶乘
-
在根据题意编写递归程序时,需要提前获取以下两个内容:
①此题的基本条件(基例)
②问题分解过程层级关系(链条) -
输入整数n,输出n的阶乘:假设目前需要求整数5的阶乘,5阶乘的结果并不能一眼得知,但是层级关系为5!=5 * 4!,4!=4 * 3!..,这样就可以将5!一步步向下分解,知道分解至1!=1 * 0!,基例为0!是一个已知值1。即针对一个正整数n,当n为0时,阶乘结果为1,当n不为0时,阶乘结果为n * (n-1)!,因此可以得出一下公式:
-
根据所获取的基例及链条所写出公式可以进行编写代码。
def fact(n): if n==0:#如果n的值为基例情况 return 1#返回基例情况的结果值 else: return n*fact(n-1)#链条关系当前n乘以(n-1)的阶乘 print(fact(5)) #120
-
在上述代码运行过程中,我们需求计算整数5的阶乘。
先将5作为fact()函数的参数会先计算 5 * 4!;
再将4作为fact()函数的参数再次传入计算4 * 3!;
再将3作为fact()函数的参数再次传入计算3 * 2!;
再将2作为fact()函数的参数再次传入计算2 * 1!;
再将1作为fact()函数的参数再次传入计算1 * 0!;
再将0作为fact()函数的参数再次传入计算。
这时会发现if判断成立,
将返回值1作为fact(0)的结果返回给0!,那么 1!=1 * 0!=1 * 1=1;
将返回值1作为fact(1)的结果返回给1!,那么 2!=2 * 1!=2 * 1=2;
将返回值2作为fact(2)的结果返回给2!,那么 3!=3 * 2!=3 * 2=6;
将返回值6作为fact(3)的结果返回给3!,那么 4!=4 * 3!=4 * 6=24;
将返回值24作为fact(4)的结果返回给4!,那么 5!=5 * 4!=5 * 24=120;
最终再将返回值120返回给fact(5)便会得到最终结果为120.
通过上述描述,我们会发现递归函数在运行过程中会经历两个过程:
①逐步分解向下调用的过程(递推)
②判断调和成立后逐步将返回值向上返回的过程(回溯)
调用函数fact(5)代码递推和回溯过程如图所示,其中蓝色箭头表示递推过程,红色箭头表示回溯过程。
三、斐波那契数列
1、斐波那契数列定义
-
斐波那契数列概念:
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契,以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列,第一项为1,第二项为1,从第三项开始,每一项的数字为前两项之和:1、2、3、5、8、13、21、34… -
兔子数列:
假设一只刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一只小兔,并且此后每个月都生一只小兔,假设兔子不会发生死亡,问:一只刚出生的兔子,n月内繁殖成多少只兔子?
兔子每月具体数量如图所示:
-
显然在图中,我们实线框表示的是成熟兔子,虚线框表示的是小兔子。从右边这一列的数字我们发现是有规律的。第一个数和第二个数为1,之后的每一个数都为
前两个数之和。
那么,我们如何将上述问题用Python代码来实现呢?首先,会发现我们已知第一个月和第二个月兔子数量必然是1,这可以作为代码的基例,除前两个月外,第n月的兔子数量为第n-1个月和第n-2个月的兔子数量之和,即f(n)=f(n-1)+f(n-2),这可以作为代码的链条,因此可以得出以下公式:
-
根据所获取的基例及链条所写出的公式可以进行编写代码。
def fibo(n): if n<=2: return 1 else: return fibo(n-1)+fibo(n-2) print(fibo(7)) #13
2、斐波那契数列实例变化
-
某种病毒具有很强的繁殖能力,从病毒粒子出生后的第五分钟开始,每分钟可以复制出一个新的病毒粒子。新出生的病毒粒子从第5分钟开始,也可以复制一个新的病毒粒子。前10分钟时的病毒粒子总数为10.,总数分别为:1,1,1,1,2,3,4,5,7,10。
-
根据题目可以分析得出前4分钟病毒粒子数量始终为1,这可作为代码的基例,除前4分钟之外第n分钟病毒粒子数为第n-1分钟和第n-4分钟病毒粒子数之和,即f(n)=f(n-1)+f(n-4),这可以作为代码链条,因此可以得出以下公式:
-
根据所获取的基例及链条所写出公式可以进行编写代码:
def virus(n): if n<=4:#如果n<=4为基例情况 return 1 return virus(n-1)+virus(n-4)#链条为参数为n-1和参数为n-4函数返回值之和 print(virus(10)) #10