簡體   English   中英

Clojure 中的遞歸斐波那契函數

[英]a recursive Fibonacci function in Clojure

我是 clojure 的新手,他想看看有什么大驚小怪的。 確定感受它的最佳方法是編寫一些簡單的代碼,我想我會從斐波那契函數開始。

我的第一個努力是:

(defn fib [x, n]
  (if (< (count x) n) 
    (fib (conj x (+ (last x) (nth x (- (count x) 2)))) n)
    x))

要使用它,我需要在調用函數時用 [0 1] 為 x 設置種子。 我的問題是,如果不將其包裝在單獨的函數中,是否可以編寫一個只需要返回元素數量的函數?

做一些閱讀讓我找到了一些更好的方法來實現相同的功能:

(defn fib2 [n]
  (loop [ x [0 1]] 
    (if (< (count x) n) 
      (recur (conj x (+ (last x) (nth x (- (count x) 2)))))
      x)))

(defn fib3 [n] 
  (take n 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))

無論如何,更多的是為了練習而不是其他任何事情,任何人都可以用更好的純遞歸斐波那契函數版本來幫助我嗎? 或者也許共享一個更好/不同的功能?

回答你的第一個問題:

(defn fib
  ([n]
     (fib [0 1] n))
  ([x, n]
     (if (< (count x) n) 
       (fib (conj x (+ (last x) (nth x (- (count x) 2)))) n)
       x)))

這種類型的函數定義稱為多元函數定義。 您可以在此處了解更多信息: http : //clojure.org/functional_programming

至於更好的 Fib 函數,我覺得你的 fib3 函數非常棒,展示了很多函數式編程概念。

這又快又酷:

(def fib (lazy-cat [0 1] (map + fib (rest fib))))

來自: http : //squirrel.pl/blog/2010/07/26/corecursion-in-clojure/

在 Clojure 中,實際上建議避免遞歸,而是使用looprecur特殊形式。 這將看似遞歸的過程變成了迭代過程,從而避免堆棧溢出並提高性能。

以下是如何使用此技術實現斐波那契數列的示例:

(defn fib [n]
  (loop [fib-nums [0 1]]
    (if (>= (count fib-nums) n)
      (subvec fib-nums 0 n)
      (let [[n1 n2] (reverse fib-nums)]
        (recur (conj fib-nums (+ n1 n2)))))))

loop結構采用一系列綁定,提供初始值和一個或多個主體形式。 在任何這些主體形式中,對recur的調用將導致使用提供的參數遞歸調用循環。

您可以使用 thrush 運算符稍微清理一下 #3(取決於您問的是誰;有些人喜歡這種風格,有些人討厭它;我只是指出這是一種選擇):

(defn fib [n] 
  (->> [0 1] 
    (iterate (fn [[a b]] [b (+ a b)]))
    (map first)
    (take n)))

也就是說,我可能會提取(take n)並讓fib函數成為一個懶惰的無限序列。

(def fib
  (->> [0 1] 
    (iterate (fn [[a b]] [b (+ a b)]))
    (map first)))

;;usage
(take 10 fib)
;;output (0 1 1 2 3 5 8 13 21 34)
(nth fib 9)
;; output  34

一個好的遞歸定義是:

(def fib 
  (memoize 
   (fn [x]
       (if (< x 2) 1
       (+ (fib (dec (dec x))) (fib (dec x)))))))

這將返回一個特定的術語。 擴展它以返回前 n 項是微不足道的:

(take n (map fib (iterate inc 0)))

對於后來者。 接受的答案是一個稍微復雜的表達:

(defn fib
  ([n]
     (fib [0 1] n))
  ([x, n]
     (if (< (count x) n) 
       (recur (conj x (apply + (take-last 2 x))) n)
       x)))

就其價值而言,這些年來,這是我對4Closure 問題 #26:斐波那契數列的解決方案

(fn [x] 
    (loop [i '(1 1)]
        (if (= x (count i))
            (reverse i)
            (recur 
              (conj i (apply + (take 2 i)))))))

無論如何,我不認為這是最佳或最慣用的方法。 我在 4Clojure 上進行練習……並仔細研究Rosetta Code 中的代碼示例的全部原因是學習

順便說一句,我很清楚斐波那契數列形式上包含 0 ......這個例子應該loop [i '(1 0)] ......但這不符合他們的規范。 盡管他們如何標記這個練習,也沒有通過他們的單元測試。 它被編寫為匿名遞歸函數,以符合 4Clojure 練習的要求……您必須在給定的表達式中“填空”。 (我發現匿名遞歸的整個概念有點令人費解;我知道(loop ... (recur ...特殊形式被限制為......但它仍然很奇怪語法給我)。

我也會考慮@[Arthur Ulfeldt] 關於原始帖子中 fib3 的評論。 到目前為止,我只使用了一次 Clojure 的iterate

這是我為計算第 n 個斐波那契數而提出的最短遞歸函數:

(defn fib-nth [n] (if (< n 2)
                n
                (+ (fib-nth (- n 1)) (fib-nth (- n 2)))))

但是,除了 'n' 的前幾個值之外,循環/遞歸的解決方案應該更快,因為 Clojure 對循環/遞歸進行了尾端優化。

這是我的方法

(defn fibonacci-seq [n]
  (cond
    (= n 0) 0
    (= n 1) 1
    :else (+ (fibonacci-seq (- n 1)) (fibonacci-seq (- n 2)))
    )
  )

暫無
暫無

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

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