我必须编写计算N个Fibonacci数的代码(其中N是函数参数)。我是LISP的新手,我正在努力学习语法。这就是我到目前为止......我觉得它很接近。
(defun fib (n)
(if (or (= n 1) (= n 2))
(print 1))
(print (+ (fib (- n 1))(fib (- n 2)))))
;;;;It should output like so:
(fib 0)
()
(fib 2)
( 1 1 )
(fib 6)
( 1 1 2 3 5 8 )
有人能帮我整理一下我的功能吗?提前谢谢!
答案 0 :(得分:2)
如果您希望(1 1)
评估REPL中的(fib 2)
,那么您不希望打印任何内容,只需要返回列表(1 1)
即可。
;; using recursion.
(defun fib (limit)
(labels ((helper (n a b)
(if (> n limit)
'()
(cons a (helper (1+ n) b (+ a b))))))
(helper 0 0 1)))
;; using tail recursion. Usually tail call optimized when
;; compiled, but it's not a requirement in the standard.
(defun fib (limit)
(labels ((helper (n a b acc)
(if (> n limit)
(nreverse acc)
(helper (1+ n) b (+ a b) (cons a acc)))))
(helper 0 0 1 '())))
;; Using loop. Never blows stack.
(defun fib (limit)
(loop :for a := 0 :then b
:and b := 1 :then (+ a b)
:repeat limit
:collect a))
我认为所有这些都具有相同的可读性,因此没有理由不选择任何实现中最安全的loop
版本。
请注意,第一个fibonacci数字为0,我的代码反映了该数字。
答案 1 :(得分:0)
你这样做的方式是tree recursive,它的运行时间会呈指数级增长。该链接具有有效的替代品。但是,如果你想保留整个序列,你可以做类似的事情,
(defun fib (num)
(let (seq)
(labels ((helper (n) ; define local helper function
(when (<= n num) ; stop when reached NUM
(if (< n 3) (push 1 seq)
(push (+ (car seq) (cadr seq)) seq)) ; sum of previous 2
(helper (1+ n))))) ; recurse
(helper 1)) ; start from first fib number
(nreverse seq))) ; reverse the result
答案 2 :(得分:0)
这是另一种可以使用辅助程序并继续解决问题的方法。
此过程是尾递归但不需要反转累积的斐波纳契数列表。
(define (fib n)
(define (aux n a b k)
(if (zero? n)
(k (list a))
(aux (sub1 n)
b
(+ a b)
(lambda (rest) (k (cons a rest))))))
(aux n 0 1 identity))
(fib 0) ;; => '(0)
(fib 1) ;; => '(0 1)
(fib 2) ;; => '(0 1 1)
(fib 10) ;; => '(0 1 1 2 3 5 8 13 21 34 55)
这里的代码是球拍,但你可以相对轻松地将它翻译成Lisp。