2010-12-07 4 views
17

Возможно ли внедрение ряда фибоначчи в Clojure с использованием reduce? Что будет содержать «аккумулятор»?Внедрение фибоначчи в Clojure с использованием карты/уменьшение

Я полагаю, что это должно быть лениво. Очевидно, как это сделать, используя рекурсию или цикл/повтор.

+1

BTW, какие побудило этот вопрос прочитать «Land of Lisp» Конрада Барски, MD. В своей главе о макросах он предостерегает от чрезмерного использования и предлагает альтернативы, используя 'map' и' reduce'. Подумал ... – Ralph

ответ

15

Вы можете использовать пару последовательных значений Фибоначчи как аккумулятора, следующим образом:

(reduce 
    (fn [[a b] _] [b (+ a b)]) ; function to calculate the next pair of values 
    [0 1]      ; initial pair of fibonnaci numbers 
    (range 10))     ; a seq to specify how many iterations you want 

=> [55 89] 

Это не особенно эффективно в связи с созданием большого количества промежуточных пар и использование последовательности лишнего диапазона для привода правильное число итераций, но это O (n) с алгоритмической точки зрения (то же самое, что и эффективное итеративное решение, и намного лучше наивного рекурсивного).

+0

Может ли это помочь, если вы использовали memoize? – Ralph

+2

@ Ralph - на самом деле это не так, поскольку функция вызывается с разными значениями каждый раз. Memoise, конечно, поможет много, если вы использовали рекурсивную реализацию .... – mikera

+0

Неплохо! Я сделал '(time (fib 10000))', используя вашу реализацию, и выполняется за 71 мс (MacBook Pro 2,66 ГГц i7). – Ralph

5

Не использовать карту/уменьшить, но повторить также можно избежать рекурсии.

(defn iter [[x y]] 
    (vector y (+ x y))) 

(nth (iterate iter [0 1]) 10000) 

Это занимает 21ms на Intel 2.4 Ghz

На той же машине, уменьшить занимает 61msec. Не знаю, почему итерация происходит быстрее.

(time (reduce 
    (fn [[a b] _] [b (+ a b)]) ; function to calculate the next pair of values 
    [0 1]      ; initial pair of fibonnaci numbers 
    (range 10000))) 
-1

Это даст вам вектор первые 1000 чисел Фибоначчи (размер range + 2), обработку второй аргумент функции (range) в качестве счетчика:

(reduce 
    (fn [a b] (conj a (+' (last a) (last (butlast a))))) 
    [0 1]      
    (range 998))