函数:递归函数
递归定义:
递归是一种计算过程,如果其中每一步都要用到前一步或前几步的结果,称为递归的。用递归过程定义的函数,称为递归函数,例如连加、连乘及阶乘等。凡是递归的函数,都是可计算的,即能行的。
递归函数定义:
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
举例: 阶乘
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
>>> fact(1)
1
>>> fact(5)
120
注意:
使用递归函数需要注意栈溢出。
RecursionError: maximum recursion depth exceeded in comparison
在Python中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
说简单点就是计算量太大了,超出限制了。
栈溢出处理办法:尾递归
将 return
函数 改为 return
数值,当然这个办法只是理论上的,实际上也行不通,Python没有尾递归优化。 ?
# 调用外部函数
def fact(n):
return fact_iter(n, 1)
# 递归函数
def fact_iter(num, product):
if num == 1:
return product
# 可以看到这里的递归采用的不是直接调用函数(做乘法)的办法,而是在函数里面进行了计算,也就是说在下次调用函数的时候是不计算的。
return fact_iter(num - 1, num * product)
练习
-
汉诺塔
移动可以用递归函数非常简单地实现。
-
请编写move(n, a, b, c)函数,它接收参数n,表示3个柱子A、B、C中第1个柱子A的盘子数量,然后打印出把所有盘子从A借助B移动到C的方法。
思路整理:
首先来看 N=1,2,3
的情况,其实超过3
个之后,利用递归函数的特性,本质上和N=3
没什么区别。
N=1 | N=2 | N=3 |
---|---|---|
A --> C | A --> B A --> C B --> C | A --> C A --> B C --> B A --> C B --> A B --> C A --> C |
可以看到,这个游戏玩法的核心就是将最底层以上的部分(记为x)放到B,然后将最底层(记为y)放到C,最后将B的部分放到C。
继续看N=3
,x从A到B的过程其实和N=2
下A到C的过程一致,只是目标位置从C替换成了B,而x从B到C的过程也其实和N=2
下A到C的过程一致,只是将起始位置从A替换成了B。
代码如下:
# -*- coding: utf-8 -*-
def move(n,a,b,c):
if n == 1:
print(a,'-->',c)
else:
move(n-1,a,c,b)
move(1,a,b,c)
move(n-1,b,a,c)
其他玩法:
斐波那契数列:
def fib(n):
if n <2:
return n
else:
return fib(n -1) + fib(n -2)