0%

递归

递归的精华是一递一归。所谓递,就是不断嵌套函数;所谓归,就是逐个将值返回。递而不归,就会越嵌套越深,直至突破内存极限而出错。

递归函数的定义有两个方面:

  1. 不断调用自己本身(只满足这个条件的是死递归)
  2. 有明确的结束条件

例如,下面的这个函数就是一个死敌归:

1
2
3
4
def func():
print(1)
func()
func()

程序并没有一直运行,输出1,而是运行到一定深度(层次)后就停止了。

这是因为 Python 为了保护计算机而设置了递归的深度限制。官方声明的限制是 1000 层,但实际测试往往在 998/997 层左右。

我们也可以修改系统设置的迭代深度限制:

1
2
import sys
sys.setrecursionlimit(800)

现在,让我们用递归写一个阶乘的函数:

1
2
3
4
5
6
7
8
def factorial(n):
if n == 1:
return 1
else:
return factorial(n - 1) * n
print(factorial(5))

返回的结果为: 120

递归的思路是:找到 f(n)f(n - 1) 之间的关系,然后将这种关系作为返回值或者其他操作。通过设置起始位置或终止位置的函数值实现函数的结束条件。

对于上个例子来说,factorial(n)factorial(n - 1) 之间的关系是 factorial(n) = factorial(n - 1) * n。而当 n1 时,factorial(1) = 1

把上面的例子拆开看就是下面这个样子:

函数层数 n 返回值
factorial(5) 5 factorial(4) * 5
1 4 factorial(3) * 4 * 5
2 3 factorial(2) * 3 * 4 * 5
3 2 factorial(1) * 2 * 3 * 4 * 5
4 1 1 * 2 * 3 * 4 * 5

有些问题使用递归解起来会有很奇妙的感觉,比如解决汉诺塔问题等。

但是因为层层嵌套,层层调用,递归非常占用内存,运行速度也相对缓慢。使用尾递归可以略微缓解这个麻烦,但也是慢,而且很难。