Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有没有办法让递归函数更快?_Python_Recursion - Fatal编程技术网

Python 有没有办法让递归函数更快?

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)

在对递归函数进行了一些研究之后,我面临着一个矛盾:一方面,用递归的方式解决问题是优雅的,而另一方面,在实践中,性能似乎很糟糕,递归调用的数量是有限的

我知道默认情况下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]
非递归方法即使在大的数字上也非常快,所以确定的问题不能是涉及的运算或数字的大小。所以我的问题是,为什么递归方法如此缓慢,有没有办法让它更快?有没有办法扩大复活深度

编辑 由于答案建议使用备忘录,我研究了它并在我的示例中实现了它:

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),因为它们都是线性的。我经常注意到使用递归的速度很慢,但没有并行比较,因为我通常编写一个或另一个版本的代码。记忆也可以称为哈希吗?在我看来,这是一个非常相似的概念。所以基本上,如果递归是我发现的解决问题的唯一方法,我应该尽可能使用记忆化,或者用其他语言编写。记忆化只是将函数的参数与根据参数计算函数的结果相关联。散列是实现它的一种方法。