Python 有没有办法让递归函数更快?
在对递归函数进行了一些研究之后,我面临着一个矛盾:一方面,用递归的方式解决问题是优雅的,而另一方面,在实践中,性能似乎很糟糕,递归调用的数量是有限的 我知道默认情况下Pythons递归深度限制为1000,但是即使是在一个简单的应用程序中,我也会在40-50次调用时得到非常糟糕的性能 让我举一个例子:Python 有没有办法让递归函数更快?,python,recursion,Python,Recursion,在对递归函数进行了一些研究之后,我面临着一个矛盾:一方面,用递归的方式解决问题是优雅的,而另一方面,在实践中,性能似乎很糟糕,递归调用的数量是有限的 我知道默认情况下Pythons递归深度限制为1000,但是即使是在一个简单的应用程序中,我也会在40-50次调用时得到非常糟糕的性能 让我举一个例子: def fibonacci(n): if n == 1 or n == 0: return 1 else: return fibonacci(n-1)
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]
非递归方法即使在大的数字上也非常快,所以确定的问题不能是涉及的运算或数字的大小。所以我的问题是,为什么递归方法如此缓慢,有没有办法让它更快?有没有办法扩大复活深度
编辑
由于答案建议使用备忘录,我研究了它并在我的示例中实现了它:
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()
(请参阅“装饰器”)
这是一种稍微高级的编码方式,但我并没有发现一种更简单的方法,即实现给定示例中的记忆。如果有更简单的实现方法,请纠正我。忽略这样一个事实,即
fibonacci()
是记忆化的教科书案例(这将使其更快),“深度和廉价”递归在普通Python中根本不是一件事
在许多语言中都有尾部调用消除。Python没有这个功能。在许多语言中,推送额外的堆栈帧非常便宜。Python中并非如此
在现实世界中,要找到这是一个问题的代码并不容易,这可能在某种程度上解释了为什么Python人员保持了它的简单性,并且总是创建真正的具有完全调试能力的堆栈框架。大多数Python应用程序都不太需要廉价的深层递归。递归函数的问题是,使用相同的参数调用相同的方法一定次数。例如,在
fibrecursive(7)
中,fibrecursive(2)
被调用4次。每次你重做同样的事情
您可以使用。简而言之,您将结果存储在一个数组中,当您调用fibrecursive(2)
时,您将检查数组是否已经存在
以下是文章中的伪代码:
function fib(n)
if key n is not in map m
m[n] := fib(n − 1) + fib(n − 2)
return m[n]
递归fib函数可能会明显更糟,因为每次“迭代”都会产生两个以上的调用。如果我没弄错的话,那就是O(n*2)对O(n)。您是否发现其他递归函数比其迭代版本慢?请阅读有关记忆的内容。递归斐波那契计算非常适合记忆。可能有助于经济化。还有:你的问题是关于一般递归还是仅仅是斐波那契?如果你考虑过这个选项,但不管怎样,这两个调用都应该存储在堆栈中,并且O(n)=O(n*2),因为它们都是线性的。我经常注意到使用递归的速度很慢,但没有并行比较,因为我通常编写一个或另一个版本的代码。记忆也可以称为哈希吗?在我看来,这是一个非常相似的概念。所以基本上,如果递归是我发现的解决问题的唯一方法,我应该尽可能使用记忆化,或者用其他语言编写。记忆化只是将函数的参数与根据参数计算函数的结果相关联。散列是实现它的一种方法。