我正在使用Python中的递归函数。我使用memoization来加速计算。
如果RecursionError
> = 333(YMMV),则以下代码段失败并显示n
(“比较时超出最大递归深度”):
from scipy.special import binom
from sys import argv
def memoized(func):
cache = {}
def new_func(*args):
if args in cache:
return cache[args]
else:
temp = cache[args] = func(*args)
return temp
return new_func
def p(N, n, k):
return binom(n, k) * (1 / N)**k * (1 - 1/N)**(n-k)
@memoized
def X(n):
if n <= 1:
return 1
s = 0
for k in range(1,n):
s += p(2, n, k) * (X(k)+X(n-k))
return (1 + (1/2)**(n-1) * X(0) + s) / (1 - (1/2)**(n-1))
n = int(argv[1])
print('efficiency: ' + str(X(n) / n))
但是,如果我将for
循环分成两个不同的总和,它会按预期工作,其值更大n
:
from scipy.special import binom
from sys import argv
def memoized(func):
cache = {}
def new_func(*args):
if args in cache:
return cache[args]
else:
temp = cache[args] = func(*args)
return temp
return new_func
def p(N, n, k):
return binom(n, k) * (1 / N)**k * (1 - 1/N)**(n-k)
@memoized
def X(n):
if n <= 1:
return 1
s1 = 0
for k in range(1,n):
s1 += p(2, n, k) * X(k)
s2 = 0
for k in range(1,n):
s2 += p(2, n, k) * X(n-k)
return (1 + (1/2)**(n-1) * X(0) + s1+s2) / (1 - (1/2)**(n-1))
n = int(argv[1])
print('efficiency: ' + str(X(n) / n))
为什么?为什么在同一行上调用两次X()
函数会影响它是否超过递归深度?
答案 0 :(得分:2)
从第二个(工作)示例开始:
for k in range(1,n):
s1 += p(2, n, k) * X(k)
您要做的第一件事就是执行X()
,其值从1开始,最多为k
。每次迭代遍历此循环时,它将最多递归X()
一次,因为所有先前的值都已被记忆。因此递归限制没有问题。然后你到了这里:
for k in range(1,n):
s2 += p(2, n, k) * X(n-k)
这只是倒数与您之前使用的n
相同的值(以相反的顺序),因此对X()
的所有调用都已被记忆。没问题。实际上,通过memoization,这个版本几乎没有递归。
现在看看你的第一个例子:
for k in range(1,n):
s += p(2, n, k) * (X(k)+X(n-k))
首次完成循环时,k
为1.您将调用X(1)
,这很好,但随后您转到X(n-1)
。由于你还没有记住X(1)
以外的任何东西,这将开始一个递归链,它将一直计入到1.这绝对容易受到递归限制的影响。