为什么我超过了最大递归深度?

时间:2013-11-06 00:12:09

标签: python recursion python-3.x fibonacci memoization

让我阻止你,我已经知道你可以调整最大允许深度。

但我认为这个用于计算第n个斐波纳契数的函数,由于试图进行记忆而不会超过它。

我在这里缺少什么?

def fib(x, cache={1:0,2:1}):
    if x is not 1 and x is not 2 and x not in cache: cache[x] = fib(x-1) + fib(x-2)
    return cache[x]

5 个答案:

答案 0 :(得分:2)

这里的问题是tdelaney在评论中指出的问题。

您正在向后填充缓存,从x向下填充到2

这足以确保您只执行线性数量的递归调用。第一次调用fib(4000)只能进行3998次递归调用。

但是3998 > sys.getcursionlimit(),所以这没有帮助。

答案 1 :(得分:2)

您的代码有效,只需设置递归限制(默认值为1000):

>>> def fib(x, cache={1:0,2:1}):
...     if x is not 1 and x is not 2 and x not in cache: cache[x] = fib(x-1) + f
ib(x-2)
...     return cache[x]
...
>>> from sys import setrecursionlimit
>>> setrecursionlimit(4001)
>>> fib(4000)
24665411055943750739295700920408683043621329657331084855778701271654158540392715
48090034103786310930146677221724629877922534738171673991711165681180811514457211
13771400656054018493704811431159158792987298892998378107544456316501964164304630
21568595514449785504918067352892206292173283858530346012173429628868997174476215
95754737778371797011268738657294932351901755682732067943003555687894170965511472
22394287423465133129791428666544293424932758353804445807459873383767095726534051
03186366562265469193320676382408395686924657068094675464095820220760924728356005
27753139995364477320639625889904027436038223654786222515006804845418392308019640
53848249082837958012652040193422565794818023898141209364892225521425081077545093
40549694342959926058170589410813569880167004050051440392247460055993434072332526
101572422443738016276258104875526626L
>>>

原因是,如果你想象一棵大树,你的根节点是4000,它连接到3999和3998.你一直沿着树的一个分支向下,直到你遇到一个基本案例。然后你回来从底部构建缓存。所以这棵树超过1000深,这就是你达到极限的原因。

答案 2 :(得分:1)

要添加讨论问题评论,想总结一下:

  • 您在递归步骤之后添加到缓存中 - 因此您的缓存没有做太多工作。
  • 您还在所有调用中引用相同的缓存值。不确定这是不是你想要的,但这就是行为。
  • 这种递归方式不是惯用的Python。但是,惯用Python是使用类似memoization装饰器的东西。有关示例,请查看此处:https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize(使用您的确切示例)

答案 3 :(得分:0)

也许这有助于形象化,出现了什么问题:

def fib(x, cache={0:..., 1:0, 2:1}):
    if x not in cache: cache[x] = fib(x-1) + fib(x-2)
    return cache[x]

for n in range(4000): fib(n)
print(fib(4000))

在您明确地自下而上构建缓存时,效果非常好。 (在运行时不评估默认参数是一件好事。)

顺便说一下:你的初始词典错了。 fib(1)是1而不是0.我在我的方法中保留了这个编号偏移量。

答案 4 :(得分:0)

让memoization很好地处理这样的问题的诀窍是从你还不知道的第一个值开始,并努力实现你需要返回的值。这意味着避免自上而下的递归。迭代计算Fibonacci值很容易。这是一个非常紧凑的版本,带有备忘录列表:

def fib(n, memo=[0,1]):
    while len(memo) < n+1:
        memo.append(memo[-2]+memo[-1])
    return memo[n]

这是一个快速演示(非常快):

>>> for i in range(90, 101):
    print(fib(i))

2880067194370816120
4660046610375530309
7540113804746346429
12200160415121876738
19740274219868223167
31940434634990099905
51680708854858323072
83621143489848422977
135301852344706746049
218922995834555169026
354224848179261915075

>>> fib(4000)
39909473435004422792081248094960912600792570982820257852628876326523051818641373433549136769424132442293969306537520118273879628025443235370362250955435654171592897966790864814458223141914272590897468472180370639695334449662650312874735560926298246249404168309064214351044459077749425236777660809226095151852052781352975449482565838369809183771787439660825140502824343131911711296392457138867486593923544177893735428602238212249156564631452507658603400012003685322984838488962351492632577755354452904049241294565662519417235020049873873878602731379207893212335423484873469083054556329894167262818692599815209582517277965059068235543139459375028276851221435815957374273143824422909416395375178739268544368126894240979135322176080374780998010657710775625856041594078495411724236560242597759185543824798332467919613598667003025993715274875