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.
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.
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.
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)
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
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];
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);
};
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
Sie müssen den berechneten Wert speichern, um das exponentielle Wachstum zu stoppen.
Hier ist ein Arbeitsbeispiel für eine schnellere Rekursion unter Verwendung von Speicher.
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 ().