按递减顺序生成Lucas数列表(使用let)

时间:2013-12-06 20:39:18

标签: scheme lisp fibonacci let

Lucas数与Fib数相似,但它以2而不是1:

开头
 2, 1, 3, 4, 7, 11, 18,

我想编写一个函数来按递减顺序生成Lucas序列号列表,直到第n个元素。

我写了这个,但我跟踪了它,实现我的列表构建功能的速度太慢了。

(defun lucas (n)
  (cond 
    ((equal n 0) 2)
    ((equal n 1) 1)
    (t (+ (lucas (- n 1))
          (lucas (- n 2))))))

这是我为list函数编写的内容。问题是(lucas n)非常慢,我不想在我已经使用let时调用辅助函数。

(defun lucas-list(n)
  (cond
   ((equal n 0) (cons n nil))
   (t (let ((n1 (lucas n)) (n2 (lucas(- n 1))))
        (cons n1 (lucas-list n2))))))

我想要实现的目标:

(lucas-list 3) => '(4 3 1 2))

感谢任何建议/帮助

4 个答案:

答案 0 :(得分:3)

pseudo - )线性时间algorithm for the Fibonacci numbers可以很容易地扩展到卢卡斯数字:

(define (lucas n)
  (let loop ((a 2) (b 1) (n n))
    (if (= n 0)
      a
      (loop b (+ a b) (- n 1)))))

这可以映射到整数以获得所需的结果:

> (map lucas '(0 1 2 3 4 5))
(2 1 3 4 7 11)
> (reverse (map lucas '(0 1 2 3 4 5)))
(11 7 4 3 1 2)

但实际上有一种更快的方法:如果你意识到上述算法在计算Lᵢ之前计算Lᵢ₋1和Lᵢ₋2,那么将它们保存在列表中应该可以节省大量时间。这给了:

(define (lucas n)
  (let loop ((a 2) (b 1) (n n) (l '()))
    (if (= n 0)
      l
      (loop b (+ a b) (- n 1) (cons a l)))))

行动中:

> (lucas 20)
(9349 5778 3571 2207 1364 843 521 322 199 123 76 47 29 18 11 7 4 3 1 2)

答案 1 :(得分:1)

优化斐波那契类型程序的一种优雅方法是使用memoïze函数缓存每个先前计算的结果:

在Racket中(使用哈希表;通用,非常好地扩展)

(define (memoize fn)
  (let ((cache (make-hash)))
    (lambda arg (hash-ref! cache arg (lambda () (apply fn arg))))))

在R6RS计划中(效率较低且不太通用,但仍然非常适用于此目的)

(define (memoize proc)
  (let ([cache '()])
    (lambda (x)
      (cond
        [(assq x cache) => cdr]
        [else (let ([ans (proc x)])
                (set! cache (cons (cons x ans) cache))
                ans)])))) 

应用于lucas过程(这类似于Python装饰器):

(define lucas
  (memoize
   (lambda (n)
     (cond
       ((= n 0) 2)
       ((= n 1) 1)
       (else   (+ (lucas (- n 1)) (lucas (- n 2))))))))

和列表程序利用累加器反转结果的事实变为:

(define (lucas-list n)
  (let loop ((i 0) (res null))
    (if (= i n)
        res
        (loop (+ i 1) (cons (lucas i) res)))))

测试:

(display (lucas-list 20))
=> {9349 5778 3571 2207 1364 843 521 322 199 123 76 47 29 18 11 7 4 3 1 2}

答案 2 :(得分:0)

怎么样:

(defun lucas-list (n)
  (if (equal n 0)
      '()
      (cons (lucas n) (lucas-list (- n 1)))))

答案 3 :(得分:0)

(defun lucas-list-decreasing (n &aux (table (make-hash-table)))
  (labels ((lucas-int (n)
              (or (gethash n table)
                  (setf (gethash n table)
                        (cond ((equal n 0) 2)
                              ((equal n 1) 1)
                              (t (+ (lucas-int (- n 1))
                                    (lucas-int (- n 2)))))))))
    (lucas-int n)
    (loop for i downfrom (1- n) downto 0
          collect (gethash i table))))

或者:

(defun lucas (n &aux (table (make-hash-table)))
  (labels ((lucas-int (n)
             (or (gethash n table)
                 (setf (gethash n table)
                       (cond ((equal n 0) 2)
                             ((equal n 1) 1)
                             (t (+ (lucas-int (- n 1))
                                   (lucas-int (- n 2)))))))))
    (values (lucas-int n)
            table)))

(defun lucas-list-decreasing (n)
  (multiple-value-bind (value table)
      (lucas n)
    (declare (ignore value))
    (loop for i downfrom (1- n) downto 0
          collect (gethash i table))))