经过一些关于递归函数的研究后,我面临矛盾:一方面以递归的方式解决问题是优雅的,另一方面在实践中表现似乎很糟糕,递归调用的数量有限。
我理解默认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。如果有更简单的实施方式请纠正我。
答案 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]