web-dev-qa-db-fra.com

Récursion rapide de Fibonacci

J'essaie de rappeler un algorithme sur la récursion de Fibonacci. Le suivant:

public int fibonacci(int n)  {
  if(n == 0)
    return 0;
  else if(n == 1)
    return 1;
  else
    return fibonacci(n - 1) + fibonacci(n - 2);
}

c'est pas ce que je cherche parce que c'est gourmand. Cela va croître de manière exponentielle (il suffit de regarder séquence Java de Fibonacci récursive - plus l'argument initial est gros, plus les appels inutiles seront faits).

Il y a probablement quelque chose comme un "décalage d'argument cyclique", où l'appel de la valeur Fibonacci précédente récupérera la valeur au lieu de la calculer à nouveau.

19
ducin

peut-être comme ça:

int fib(int term, int val = 1, int prev = 0)
{
 if(term == 0) return prev;
 return fib(term - 1, val+prev, val);
}

cette fonction est queue récursive. cela signifie qu'il pourrait être optimisé et exécuté de manière très efficace. En fait, il est optimisé dans une simple boucle.

40
duedl0r

Ce type de problèmes sont de type récurrence linéaire et ils sont résolus plus rapidement via l'exponiation de matrice rapide. Voici le blogpost qui décrit ce type d’approche de manière concise.

9
plesiv

Vous pouvez faire une version assez rapide de Fibonacci récursif en utilisant memoization (ce qui signifie: stocker les résultats précédents pour éviter de les recalculer). Par exemple, voici une preuve de concept en Python, dans laquelle un dictionnaire est utilisé pour enregistrer les résultats précédents:

results = { 0:0, 1:1 }

def memofib(n):
    if n not in results:
        results[n] = memofib(n-1) + memofib(n-2)
    return results[n]

Il retourne rapidement pour les valeurs d'entrée qui bloqueraient normalement la version récursive "normale". Gardez simplement à l'esprit qu'un type de données int ne suffira pas pour conserver des résultats volumineux et qu'il est recommandé d'utiliser des entiers à précision arbitraire.

Une option totalement différente - réécrire cette version itérative ...

def iterfib(n):
    a, b = 0, 1
    for i in xrange(n):
        a, b = b, a + b
    return a

... en tant que fonction queue récursive, appelée loop dans mon code:

def tailfib(n):
    return loop(n, 0, 1)

def loop(i, a, b):
    if i == 0:
        return a
    return loop(i-1, b, a+b)
7
Óscar López

J'ai trouvé un article intéressant sur le problème de fibonacci

ici l'extrait de code

# Returns F(n)
def fibonacci(n):
    if n < 0:
        raise ValueError("Negative arguments not implemented")
    return _fib(n)[0]


# Returns a Tuple (F(n), F(n+1))
def _fib(n):
    if n == 0:
        return (0, 1)
    else:
        a, b = _fib(n // 2)
        c = a * (2 * b - a)
        d = b * b + a * a
        if n % 2 == 0:
            return (c, d)
        else:
            return (d, c + d)

# added iterative version base on C# example
def iterFib(n):
    a = 0
    b = 1
    i=31
    while i>=0:
        d = a * (b * 2 - a)
        e = a * a + b * b
        a = d
        b = e
        if ((n >> i) & 1) != 0:
            c = a + b;
            a = b
            b = c
        i=i-1
    return a
3
Moch Lutfi

Imaginons que vous souhaitiez avoir le nième nombre puis créez un tableau contenant les nombres précédents

int a[n];
a[0] = 0;
a[1] =1;
a[i] = n[i-1]+n[n-2];
2
monkeyking

Un exemple en JavaScript utilisant la récursivité et un cache initialisé paresseux pour une efficacité accrue:

var cache = {};

function fibonacciOf (n) {
  if(n === 0) return 0;
  if(n === 1) return 1;
  var previous = cache[n-1] || fibonacciOf(n-1);
  cache[n-1] = previous;
  return previous + fibonacciOf(n-2);
};
1
Sebastian Sastre

l'algorithme de duedl0r traduit en swift:

func fib(n: Int, previous: (Int, Int) = (0,1)) -> Int {
    guard n > 0 else { return 0 }
    if n == 1 { return previous.1 }
    return fib(n - 1, previous: (previous.1, previous.0 + previous.1))
}

exemple travaillé:

fib(4)
= fib(4, (0,1) )
= fib(3, (1,1) )
= fib(2, (1,2) )
= fib(1, (2,3) )
= 3
0
Ken Ko

Vous devez mémoriser la valeur calculée pour arrêter la croissance exponentielle.

  1. Utilisez simplement un tableau pour stocker la valeur. 
  2. Vérifiez le tableau si vous l'avez déjà calculé.
  3. S'il le trouve, utilisez-le ou calculez-le ou stockez-le.

Voici un exemple de travail pour une récursivité plus rapide en utilisant la mémoire.

Calcul du nombre de fibonacci

0
kta

Un bon algorithme pour les calculs rapides de fibonacci est (en python):

def fib2(n):
    # return (fib(n), fib(n-1))
    if n ==  0: return (0,  1)
    if n == -1: return (1, -1)
    k, r = divmod(n, 2) # n=2k+r
    u_k, u_km1 = fib2(k)
    u_k_s, u_km1_s = u_k**2, u_km1**2  # Can be improved by parallel calls
    u_2kp1 = 4 * u_k_s - u_km1_s + (-2 if k%2 else 2)
    u_2km1 = u_k_s + u_km1_s
    u_2k   = u_2kp1 - u_2km1
    return (u_2kp1, u_2k) if r else (u_2k, u_2km1)

def fib(n):
    k, r = divmod(n, 2) # n=2k+r
    u_k, u_km1 = fib2(k)
    return (2*u_k+u_km1)*(2*u_k-u_km1)+(-2 if k%2 else 2) if r else u_k*(u_k+2*u_km1)

Si vous avez besoin d'un calcul très rapide, créez un lien vers libgmp et utilisez les fonctions mpz_fib_ui () ou mpz_fib2_ui ().

0
HNoob