【发布时间】:2017-10-27 07:36:49
【问题描述】:
在对递归函数进行一些研究后,我面临着矛盾:一方面以递归方式解决问题很优雅,而另一方面在实践中性能似乎很糟糕,递归调用的数量有限。
我知道默认情况下 Python 的递归深度限制为 1000,但是即使在一个简单的应用程序中,我在 40 到 50 次调用时性能也很差。
我举个例子:
def fibonacci(n):
if n == 1 or n == 0:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
我 PC 上的这个简单递归函数即使对于低 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]
即使在大数字上,非递归方式也非常快,因此问题肯定不是涉及的操作或数字的大小。所以我的问题是为什么递归方式这么慢,有没有办法让它更快?有没有办法扩大递归深度?
编辑 由于答案建议使用记忆化,因此我对其进行了研究并在我的示例中实现了它:
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()(请参阅“装饰器”)
这是一种稍微先进的编码方式,但我没有找到更简单的方法是为给定的示例实现记忆。如果有更简单的实现方式请纠正我。
【问题讨论】:
-
递归 fib 函数可能明显更糟,因为每次“迭代”都会对自身产生 2 次以上的调用。如果我没记错的话,那就是 O(n*2) vs O(n)。您是否发现其他递归函数比它们的迭代版本慢?
-
阅读记忆化。
-
递归斐波那契计算非常适合记忆。 stackoverflow.com/questions/1988804/…
-
docs.python.org/3/library/functools.html#functools.lru_cache 可能有助于记忆化。并且:您的问题是关于一般递归还是斐波那契?
-
如果正在考虑该选项,但无论如何都应该将两个调用都存储在堆栈中,并且我记得 O(n) = O(n*2) 因为两者都是线性的。我经常注意到使用递归的速度很慢,但没有进行并排比较,因为我通常编写一个或另一个版本的代码。