有什么办法让递归函数更快?

时间:2017-05-26 11:58:15

标签: python recursion

经过一些关于递归函数的研究后,我面临矛盾:一方面以递归的方式解决问题是优雅的,另一方面在实践中表现似乎很糟糕,递归调用的数量有限。

我理解默认Pythons的递归深度限制为1000,但即使在一个简单的应用程序中,我也会在40-50次调用时遇到非常糟糕的性能。

让我举个例子:

def fibonacci(n):
    if n == 1 or n == 0:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

这个简单的递归功能在我的电脑上花费了大量的时间来解决,即使是低n。为了测试,我还写了另一个函数:

def fib_nonrecursive(n):
    fib_seq = [1, 1]
    for i in range(2, n+1):
        value = fib_seq[i-1] + fib_seq[i-2]
        fib_seq.append(value)        
    return fib_seq[i]

非递归方式即使在大数字上也非常快,因此确定性问题不能涉及操作或数字大小。所以我的问题是为什么递归方式如此缓慢,有没有办法让它更快?有什么办法可以扩大反复深度吗?

修改 由于回答建议使用memoization我调查并在我的例子中实现它:

def mem(f):
    memory = {}
    def inner_function(x):
        if x not in memory:            
            memory[x] = f(x)
            return memory[x]
        else:
            return memory[x]
    return inner_function

@mem
def fibonacci(n):
    if n == 1 or n == 0:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

相同的mem(f)可以与其他递归函数f一起使用。必须包含@mem部分才能将f作为参数传递给mem()(请参阅“装饰器”) 它是稍微先进的代码方式,但我没有发现更容易实现给定示例的memoization。如果有更简单的实施方式请纠正我。

2 个答案:

答案 0 :(得分:2)

忽略fibonacci()是一个用于记忆的教科书案例(这会使其更快),"深度和便宜"递归根本不是普通Python中的东西。

在许多语言中都有尾部呼叫消除。 Python没有这个。在许多语言中,推动额外的堆栈框架非常便宜。在Python中不是这样。

找到真正的代码并不容易,这是一个问题,这可能会解释为什么Python人员保持简单并始终创建具有完全调试能力的真正的堆栈帧。在大多数Python应用程序中,对于廉价和深度递归的需求并不大。

答案 1 :(得分:1)

递归函数的问题是您使用相同的参数调用相同的方法一定次数。例如,在fibrecursive(7)中,fibrecursive(2)被调用4次。每次重做同样的事情。

您可以使用dynamic programming提高效果。简而言之,您将结果存储在一个数组中,当您调用fibrecursive(2)时,您将检查数组是否已存在。

以下是文章中的伪代码:

function fib(n)
    if key n is not in map m 
        m[n] := fib(n − 1) + fib(n − 2)
    return m[n]