python 2.7 - 递归Fibonacci爆炸

时间:2012-10-10 23:56:51

标签: python recursion

我有两个函数fib1fib2来计算Fibonacci。

def fib1(n):
    if n < 2:
        return 1
    else:
        return fib1(n-1) + fib1(n-2)

def fib2(n):
    def fib2h(s, c, n):
        if n < 1:
            return s
        else:
            return fib2h(c, s + c, n-1)
    return fib2h(1, 1, n)

fib2正常工作,直到它超出递归限制。如果理解正确,Python不会针对尾递归进行优化。我很好。

即使fib1值非常小,n让我开始放慢速度也会停止。为什么会这样?为什么它在缓慢之前没有达到递归限制?

3 个答案:

答案 0 :(得分:6)

基本上,你通过一遍又一遍地计算相同n值的fib1来浪费大量时间。您可以轻松地记住这个功能

def fib1(n, memo={}):
    if n in memo:
        return memo[n]
    if n < 2:
        memo[n] = 1
    else:
        memo[n] =  fib1(n-1) + fib1(n-2)
    return memo[n]

您会注意到我使用空dict作为默认参数。这通常是一个坏主意,因为相同的dict被用作每个函数调用的默认值。

在这里,我利用它来记住我计算的每个结果

您还可以使用0和1填充备忘录,以避免需要n < 2测试

def fib1(n, memo={0: 1, 1: 1}):
    if n in memo:
        return memo[n]
    else:
        memo[n] =  fib1(n-1) + fib1(n-2)
    return memo[n]

哪个成为

def fib1(n, memo={0: 1, 1: 1}):
    return memo.setdefault(n, memo.get(n) or fib1(n-1) + fib1(n-2))

答案 1 :(得分:5)

你的问题不是python,而是你的算法。 fib1tree recursion的一个很好的例子。您可以找到此特定算法的证明here on stackoverflow(〜θ(1.6 n ))。

n=30(显然来自评论)需要大约三分之一秒。如果计算时间扩展为1.6^n,我们希望n=100可以采用2.1 million years.

答案 2 :(得分:2)

想想每个中的递归树。第二个版本是递归的单个分支,在函数调用的参数计算中添加,然后它返回值。如您所知,Python不需要尾递归优化,但如果尾调用优化是解释器的一部分,也可以触发尾递归优化。

另一方面,第一个版本在每个级别需要2个递归分支!因此,该功能的潜在执行次数大幅增加。不仅如此,大部分工作都重复了两次!考虑:fib1(n-1)最终再次调用fib1(n-1),这与从第一个调用帧的引用点调用fib1(n-2)相同。但是在计算出该值之后,必须再次将其添加到fib1(n-2)的值中!所以这项工作不必要地重复多次。