簡體   English   中英

在python中使用遞歸計算斐波那契數時的問題

[英]Issue when computing fibonacci number with recursion in python

我有這段代碼用於使用緩存(字典)計算斐波那契數。

cache = {} 
def dynamic_fib(n):
    print n
    if n == 0 or n == 1:
        return 1
    if not (n in cache):
        print "caching %d" % n
        cache[n] = dynamic_fib(n-1) + dynamic_fib(n-2)

    return cache[n]

if __name__ == "__main__":
    start = time.time()
    print "DYNAMIC: ", dynamic_fib(2000)
    print (time.time() - start)

我可以使用較小的數字來正常工作,但是輸入超過1000則似乎停止了。

這是將2000作為輸入的結果。

....
caching 1008
1007
caching 1007
1006
caching 1006
1005
caching 1005

這是將1000作為輸入的結果。

....
8
caching 8
7
caching 7
6
caching 6
5
caching 5

看起來像是將995存儲到字典中之后,它就掛了。 這可能有什么問題? 我可以使用哪種調試技術來查看python出了什么問題?

我在Mac OS X 10.7.5上運行python,我有4G字節的RAM,所以我認為一些KB(甚至MB)的內存使用沒有太大關系。

Python的默認遞歸限制設置為1000。您需要在程序中增加它。

import sys

sys.setrecursionlimit(5000)

來自: http : //docs.python.org/2/library/sys.html#sys.setrecursionlimit

sys.setrecursionlimit(限制)

 Set the maximum depth of the Python interpreter stack to limit. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. The highest possible limit is platform-dependent. A user may need to set the limit higher when she has a program that requires deep recursion and a platform that supports a higher limit. This should bedone with care, because a too-high limit can lead to a crash. 

通過將緩存存儲為字典,實際上並不會獲得任何好處,因為要計算f(n)您需要知道f(n-1) (和f(n-2) )。 換句話說,您的字典將始終具有從2-n開始的鍵。 您也可以只使用一個列表(它只是一個額外的2個元素)。 這是一個可以正確緩存且未達到遞歸限制(永遠)的版本:

import time
cache = [1,1]

def dynamic_fib(n):
    #print n
    if n >= len(cache):
        for i in range(len(cache),n):
            dynamic_fib(i)

        cache.append(dynamic_fib(n-1) + dynamic_fib(n-2))
        print "caching %d" % n

    return cache[n]

if __name__ == "__main__":
    start = time.time()
    a = dynamic_fib(4000)
    print "Dynamic",a
    print (time.time() - start)

請注意,使用dict可以完成相同的操作,但是我幾乎肯定列表會更快。


只是為了好玩,這里有很多選擇(以及時間安排!):

def fib_iter(n):
    a, b = 1, 1
    for i in xrange(n):
        a, b = b, a + b
    return a

memo_iter = [1,1]
def fib_iter_memo(n):
    if n == 0:
        return 1
    else:
        try:
            return memo_iter[n+1]
        except IndexError:
            a,b = memo_iter[-2:]
            for i in xrange(len(memo_iter),n+2):
                a, b = b, a + b
                memo_iter.append(a)
            return memo_iter[-1]

dyn_cache = [1,1]
def dynamic_fib(n):
    if n >= len(dyn_cache):
        for i in xrange(len(dyn_cache),n):
            dynamic_fib(i)

        dyn_cache.append(dynamic_fib(n-1) + dynamic_fib(n-2))

    return dyn_cache[n]

dyn_cache2 = [1,1]
def dynamic_fib2(n):
    if n >= len(dyn_cache2):
        for i in xrange(len(dyn_cache2),n):
            dynamic_fib2(i)

        dyn_cache2.append(dyn_cache2[-1] + dyn_cache2[-2])

    return dyn_cache2[n]

cache_fibo = [1,1]
def dyn_fib_simple(n):
   while len(cache_fibo) <= n:
        cache_fibo.append(cache_fibo[-1]+cache_fibo[-2])
   return cache_fibo[n]

import timeit
for func in ('dyn_fib_simple','dynamic_fib2','dynamic_fib','fib_iter_memo','fib_iter'):
    print timeit.timeit('%s(100)'%func,setup='from __main__ import %s'%func),func


print fib_iter(100)
print fib_iter_memo(100)
print fib_iter_memo(100)
print dynamic_fib(100)
print dynamic_fib2(100)
print dyn_fib_simple(100)

結果:

0.269892930984 dyn_fib_simple
0.256865024567 dynamic_fib2
0.241492033005 dynamic_fib
0.222282171249 fib_iter_memo
7.23831701279 fib_iter
573147844013817084101
573147844013817084101
573147844013817084101
573147844013817084101
573147844013817084101
573147844013817084101

免費版本:

def fibo(n):
   cache=[1,1]
   while len(cache) < n:
       cache.append(cache[-1]+cache[-2])
   return cache

這可能是由於堆棧深度的限制,導致RuntimeError。 您可以通過調用來增加堆棧的遞歸限制

sys.setrecursionlimit(<number>)

sys模塊的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM