Saltar al contenido

¿Generando series de Fibonacci en Lisp usando recursividad?

Después de de nuestra prolongada búsqueda de datos pudimos resolver este apuro que pueden tener algunos de nuestros lectores. Te brindamos la solución y nuestro deseo es resultarte de mucha ayuda.

Solución:

Sí:

(defun fibonacci (n &optional (a 0) (b 1) (acc ()))
  (if (zerop n)
      (nreverse acc)
      (fibonacci (1- n) b (+ a b) (cons a acc))))

(fibonacci 5) ; ==> (0 1 1 2 3)

La lógica detrás de esto es que necesitas conocer los dos números anteriores para generar el siguiente.

a     0 1 1 2 3 5 ...
b     1 1 2 3 5 8 ...
new-b 1 2 3 5 8 13 ...     

En lugar de devolver solo un resultado, acumulo todos los a-s hasta n es cero

EDITAR Sin reversa es un poco más ineficiente:

(defun fibonacci (n &optional (a 0) (b 1))
  (if (zerop n)
      nil
      (cons a (fibonacci (1- n) b (+ a b)))))

(fibonacci 5) ; ==> (0 1 1 2 3)

El programa imprime el número n de la serie de Fibonacci.

Este programa no imprime nada. Si está viendo el resultado, probablemente se deba a que lo está llamando desde el comando read-eval-impresión-loop (REPL), que lee un formulario, lo evalúa y luego huellas dactilares el resultado. Por ejemplo, podrías estar haciendo:

CL-USER> (fibonacci 4)
2

Sin embargo, si envolvió esa llamada en otra cosa, verá que no está imprimiendo nada:

CL-USER> (progn (fibonacci 4) nil)
NIL

Como tiene esto escrito, será difícil modificarlo para imprimir cada número de Fibonacci solo una vez, ya que hace muchos cálculos redundantes. Por ejemplo, la llamada a

(fibonacci (- n 1))

calculará (fibonacci (- n 1)), pero también lo hará la llamada directa a

(fibonacci (- n 2))

Eso significa que probablemente no desee que cada llamada fibonacci para imprimir toda la secuencia. Sin embargo, si lo hace, tenga en cuenta que (print x) devuelve el valor de x, por lo que simplemente puede hacer:

(defun fibonacci(n)
  (cond
    ((eq n 1) 0)
    ((eq n 2) 1)
    ((print (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))))
CL-USER> (progn (fibonacci 6) nil)

1 
2 
1 
3 
1 
2 
5 
NIL

Verá algunas partes repetidas allí, ya que hay un cálculo redundante. Sin embargo, puede calcular la serie de manera mucho más eficiente comenzando desde los dos primeros números y contando:

(defun fibonacci (n)
  (do ((a 1 b)
       (b 1 (print (+ a b)))
       (n n (1- n)))
      ((zerop n) b)))
CL-USER> (fibonacci 6)

2 
3 
5 
8 
13 
21 

Una opción para mantener la estructura básica que usó es pasar un indicador adicional a la función que le indica si desea imprimir o no:

(defun fibo (n printseq)
  (cond
    ((= n 1) (if printseq (print 0) 0))
    ((= n 2) (if printseq (print 1) 1))
    (T
     (let ((a (fibo (- n 1) printseq))
           (b (fibo (- n 2) NIL)))
       (if printseq (print (+ a b)) (+ a b))))))

La idea es que cuando realiza las dos llamadas recursivas solo en la primera, pasa la bandera sobre hacer la impresión y en la segunda llamada simplemente pasa NIL para evitar imprimir nuevamente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *