2017-07-02 50 views
2

所以這裏有一個斐波那契項,計算功能(在Ruby中):斐波納契哈斯克爾

def fibfast(n) 
    xs = [0,1] 
    (n-1).times do |i| 
    next_term = xs.sum 
    xs[0]=xs[1] 
    xs[1]=next_term 
    end 
    return xs[1] 
end 

我敢肯定它具有恆定的空間複雜度(其只存儲數據是XS),和線性時間複雜度(它使用一個循環來計算序列的第n項)。

我的問題是,函數是遞歸的嗎?它使用它計算的值來執行更多計算,但從未自行調用。我的另一個問題是,我如何在Haskell中獲得同樣的時空緊湊性?我發現Haskell函數的空間複雜度大於O(1),返回一個完整的術語列表,並且/或者它們的時間複雜度大於O(n),因爲它們使用了典型的遞歸定義。

任何想法感激,謝謝!

+2

爲什麼會遞歸確定指標有較高的時間複雜度。 –

+0

遞歸定義的斐波那契函數需要更多的計算,我相信它的複雜度爲O(2^n)。 –

+0

@ZacharyBechnoefer:如果你使用*累加器*,則不行。 –

回答

4

我的問題是,函數是遞歸的嗎?它使用它計算的值來執行更多計算,但從未自行調用。

沒有:遞歸意味着東西本身來定義。 fibfast函數本身沒有定義。

我的另一個問題是,我如何在Haskell中獲得相同的時空緊湊性?我發現Haskell函數的空間複雜度大於O(1),返回一個完整的術語列表,並且/或者它們的時間複雜度大於O(n),因爲它們使用了典型的遞歸定義。

您可以使用以下功能:

fibfast :: Int -> Int 
fibfast n = fib' 0 1 n 
    where fib' a b n | n <= 1 = b 
        | otherwise = fib' b (a+b) (n-1) 

所以在這裏我們定義了一個遞歸函數fib'和使用兩個累加器a和最後兩個值存儲在序列中b。每次迭代,兩個更新,我們減少我們必須做的迭代次數,直到它遇到一個小於或等於1的數字n,在這種情況下,我們返回第二個累加器。

一個問題可能是Haskell通常不會熱切地評估表達式,而是懶洋洋地。所以它存儲a+b而不是計算a+b。因此,表達樹很快就會像a+b+a+b+a+b...一樣快速增長。我們可以例如使用爆炸模式

{-# LANGUAGE BangPatterns #-} 

fibfast :: Int -> Int 
fibfast n = fib' 0 1 n 
    where fib' a !b !n | n <= 1 = b 
         | otherwise = fib' b (a+b) (n-1) 
+0

非常酷!你有沒有研究過這個課程?像,算法設計什麼的?謝謝! –

+1

@ZacharyBechhoefer:沒有。其實我第一次在邏輯編程課程(Prolog)中瞭解了累加器。但是邏輯和函數式編程有一些共同的背景。 –

+4

@ZacharyBechhoefer這是(在其他地方,我敢肯定)在結構和計算機程序解釋(SICP),在本書的早期階段教過 - 它實際上也使用斐波那契作爲示例程序,比較迭代和遞歸*程序* vs *進程* – naomik