簡體   English   中英

當字典在函數中時,為什么我的 Fibonacci 需要這么長時間?

[英]Why does my Fibonacci take so long when the dictionary is in the function?

這里我有一些代碼來返回斐波那契數的最后一位。 當我將緩存字典放在函數中時,程序對小 n 工作正常。 當我嘗試像 300 這樣更大的 n 時,程序將永遠運行。 但是,當我將字典設為全局時,我會立即得到更大的 n(例如 300)的結果。是什么導致在函數中聲明的字典與在函數外部聲明的字典之間存在如此明顯的性能差異?

def fib_last_digit_mem(n):
    cache = {}

    if n in cache:
        return cache[n]

    if(n <= 1):
        return n

    fib = (fib_last_digit_mem(n-1) + fib_last_digit_mem(n-2))%10
    cache[n] = fib
    return fib


由於這是一個遞歸函數,如果您在函數內部實例化緩存,則每次函數遞歸時都會再次實例化。 這也意味着緩存總是空的,所以if n in cache你永遠不會走捷徑

您實際上並沒有緩存任何內容,因為每次調用該函數時,本地var cache都被初始化為一個空字典。 當然,一旦計算出值,就將其添加到字典中。 但隨后您返回: cache超出范圍, dict被垃圾收集。

您需要一些對存在於fib_last_digit_mem之外cache的引用,但這不一定需要是全局變量。

考慮:

def make_cached_fib():
    cache = {}
    def _(n):
        if n in cache:
            return cache[n]
        if n <= 1:
            return n
        fib = (_(n-1) + _(n-2)) % 10
        cache[n] = fib
        return fib
    return _

fib_last_digit_mem = make_cached_fib()

在這里,緩存不是全局的; 它在定義fib_last_digit_mem的范圍內。 一旦make_cached_fib返回,對緩存的唯一引用就是fib_last_digit_mem本身持有的引用。

您在遞歸調用的函數中實例化緩存。 這會導致兩個問題:

1) 每次進行遞歸調用時,您都必須實例化一個緩存,這會消耗一些性能,但創建過程並不是您的代碼運行緩慢的原因。

2)真正的原因甚至更大的問題是你沒有對你的緩存做任何事情。 動態規划允許您重用以前計算的結果,因此您不必再次計算它們。 您將這些結果保存在緩存中。 但是因為每次調用該方法時都在實例化緩存,所以所有遞歸調用最終都會擁有一個自己的空本地緩存,而不是共享一個全局緩存,這有助於您避免再次計算先前計算的結果。

例子:

如果您全局聲明緩存並計算fibonacci(10) ,則最后一個操作只需從緩存中獲取fibonacci(9)的結果並向其添加另一個數字。 這是計算下一個第 n 個斐波那契數的唯一加法。 在你的情況下,你不是僅僅得到fibonacci(9)的結果並向它添加一個數字,你實際上是在再次計算fibonacci(9) ,這意味着你必須再次計算 fibonacci fibonacci(8)等等......這會導致不好的沒有動態規划的性能(全局緩存)

暫無
暫無

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

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