如果不加以优化的话,递归很容易出现重复计算的问题。比如前面计算斐波那契数列,根据公式有F(n) = F(n-1) + F(n-2)。这意味着为了计算F(8),必须计算F(7)和F(6)。而为了计算F(7),必须计算F(6)和F(5),......。这里F(6)就被计算了两次。一般地,递归程序越靠近边界,重复计算的次数就会呈指数增加。当求F(36)时,电脑已经完全僵死,没有反应了。
那怎么解决这个问题呢?规范的方法是这样的:
- 要保证递归程序除了参数之外没有读写任何外部数据。这是为了保证程序的优化只在程序内部发生作用,不会影响到外部环境。这个特点称为函数不变性(Immutable),与数据不变性相对应。函数不变性的另一种理解是,只要参数相同,函数总是返回相同的结果。比如随机数发生函数numpy.random.randint()以及日期函数time.time()就不具有不变性。一般地,如果函数是可变的,可以把相关的外部数据引入参数列表中就能解决这个问题。另外,如果函数只是读取外部数据,没有改写它,那函数也是不可变的。
- 在函数的参数中增加一个字典型(dict)的参数d,作用是保存递归调用的中间结果。字典是一种能够根据键获取值的数据类型,Python中的字典相当于Java中的Map。当发生重复调用时,从d中直接获取结果即可,不必进行重复的递归调用。
- 把函数当前所有参数集中起来构成一个元组t,在递归假设和递归推导之前看看t是否在d中存在,如果存在,说明本次调用是一个重