web-dev-qa-db-de.com

Schnelle Fibonacci-Rekursion

Ich versuche, einen Algorithmus für die Fibonacci-Rekursion zu erinnern. Folgende:

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

ist nicht was ich suche, weil es gierig ist. Dies wird exponentiell wachsen (schauen Sie sich nur Java-rekursive Fibonacci-Sequenz an - je größer das erste Argument, desto mehr unbrauchbare Aufrufe werden gemacht.

Es gibt wahrscheinlich so etwas wie eine "zyklische Argumentverschiebung", bei der das Aufrufen des vorherigen Fibonacci-Werts den Wert abruft, anstatt ihn erneut zu berechnen.

19
ducin

vielleicht so:

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

diese Funktion ist rekursiv. Dies bedeutet, dass es sehr effizient optimiert und ausgeführt werden kann. Tatsächlich wird es zu einer einfachen Schleife optimiert.

40
duedl0r

Diese Art von Problemen sind lineare Wiederholungstypen und werden am schnellsten durch schnelle Matrixexponentiation gelöst. Hier ist der blogpost , der diese Herangehensweise kurz beschreibt.

9
plesiv

Sie können eine ziemlich schnelle Version von rekursivem Fibonacci erstellen, indem Sie memoization verwenden (dh vorherige Ergebnisse speichern, um eine Neuberechnung zu vermeiden). Hier ist zum Beispiel ein Proof of Concept in Python, wo ein Wörterbuch zum Speichern vorheriger Ergebnisse verwendet wird:

results = { 0:0, 1:1 }

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

Es wird schnell für Eingabewerte zurückgegeben, die normalerweise die "normale" rekursive Version blockieren würden. Beachten Sie jedoch, dass ein int-Datentyp nicht ausreicht, um große Ergebnisse zu speichern, und es wird empfohlen, beliebige Integer mit beliebiger Genauigkeit zu verwenden.

Eine ganz andere Möglichkeit - diese iterative Version neu schreiben ...

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

... als rekursive Funktion, die in meinem Code loop heißt:

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

Ich habe einen interessanten Artikel über das Fibonacci-Problem gefunden

hier das Code-Snippet

# 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

Angenommen, Sie möchten die n-te Fib-Nummer, dann erstellen Sie ein Array mit den vorhergehenden Nummern

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

Ein Beispiel in JavaScript, das Rekursion und einen langsam initialisierten Cache verwendet, um die Effizienz zu erhöhen:

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

duedl0rs Algorithmus übersetzt nach 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))
}

gearbeitetes Beispiel:

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

Sie müssen den berechneten Wert speichern, um das exponentielle Wachstum zu stoppen.

  1. Verwenden Sie einfach ein Array, um den Wert zu speichern. 
  2. Überprüfen Sie das Array, wenn Sie es bereits berechnet haben.
  3. Wenn es es findet, verwenden Sie es oder berechnen Sie es anderweitig und speichern Sie es.

Hier ist ein Arbeitsbeispiel für eine schnellere Rekursion unter Verwendung von Speicher.

Berechnung der Fibonacci-Zahl

0
kta

Ein guter Algorithmus für schnelle Fibonacci-Berechnungen ist (in 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)

Wenn Sie eine sehr schnelle Berechnung benötigen, stellen Sie eine Verknüpfung zu libgmp her und verwenden Sie die Funktionen mpz_fib_ui () oder mpz_fib2_ui ().

0
HNoob