Fibonacci rekursiv mittels Cache

mseep

Mitglied
Hi Leute,

meine Aufgabe ist es die n-te Zahl der Fibonacci-Folge rekursiv zu berechnen, wobei die Methode mittels eines Caches für jedes n höchstens einmal aufgerufen werden soll, sodass am Ende die Methode maximal n+1 mal aufgerufen wurde. Ich hab viel nachgedacht, viel rumprobiert, komme aber leider nicht unter 2n-3 Aufrufe. Ich wär Euch sehr dankbar, wenn Ihr mir helfen könntet meinen Denkfehler zu finden, bzw meine Gedanken in die richtige Richtung zu lenken:

Java:
public class FibonacciCache {

    private static int aufrufe = 0;
    private static int fib(int n, int[] cache) {
        aufrufe++;
        if(n <= 0){
            return 0;
        }
        
        cache[0] = 1;
       
        if(cache[n-1] != 0){
            return cache[n-1];
        }
       
        if(cache [n-2] != 0){
            int result = cache[n-2] + fib(n - 2, cache);
            cache[n-1] = result;
            return result;
        }
        else if(cache [n-3] != 0){
            int result = fib(n-1, cache) + cache[n-3];
            cache[n-1] = result;
            return result;
        }
        else if(cache[n-2] != 0 && cache[n-3] != 0){
            int result = cache[n-2] + cache[n-3];
            cache[n-1] = result;
            return result;
        }
        else{
        int result = fib(n-1, cache) + fib(n - 2, cache);
        cache[n-1] = result;
        return result;
        }
    }

   
    public static void main(String []args) {
        int n = Integer.parseInt(args[0]);
        int[] cache = new int[n];
        System.out.println("fib(" + n + ") = " + fib(n, cache) + " (Aufrufe = " + aufrufe + ")");
       
        //for(int i = 0; i < n; i++){
        //    System.out.println(cache[i]);
        //}
    }
Vielen Dank im Voraus!
 

Joose

Top Contributor
Eines der Probleme ist die Reihenfolge bei den if/else Bedingungen

Java:
  if(cache [n-2] != 0){
  int result = cache[n-2] + fib(n - 2, cache);
  cache[n-1] = result;
  return result;
  }
  else if(cache [n-3] != 0){
  int result = fib(n-1, cache) + cache[n-3];
  cache[n-1] = result;
  return result;
  }
  else if(cache[n-2] != 0 && cache[n-3] != 0){
  int result = cache[n-2] + cache[n-3];
  cache[n-1] = result;
  return result;
  }
  else{
       int result = fib(n-1, cache) + fib(n - 2, cache);
       cache[n-1] = result;
       return result;
  }
  }

Du fragst zuerst einzeln nach ob "cache[n-2]" bzw. "cache[n-3]" ungleich 0 sind und dann erst ob beiden ungleich 0 sind.
Sobald einer der beiden Plätze im Cache != 0 ist wird das 3.else-if nicht mehr betreten, da davor eine der beiden Bedingungen erfüllt ist.
 

mseep

Mitglied
Eines der Probleme ist die Reihenfolge bei den if/else Bedingungen



Du fragst zuerst einzeln nach ob "cache[n-2]" bzw. "cache[n-3]" ungleich 0 sind und dann erst ob beiden ungleich 0 sind.
Sobald einer der beiden Plätze im Cache != 0 ist wird das 3.else-if nicht mehr betreten, da davor eine der beiden Bedingungen erfüllt ist.
jap ist mir auch aufgefallen :/ überprüf ich zuerst ob beide gleich null sind, krieg ich ne ArrayOutOfBounds-Exception, da ich für n = 2 die -1-te stelle im cache auf ungleichheit mit 0 überprüfe, welche ja gar nicht existiert. dann muss ich da wohl noch rumschrauben.

Moin,

Ach ... und warum nicht ?? :eek:
Da steht doch alles drin :confused:

Gruß Klaus
dann muss ich blind sein :D hab da keinen lörungsansatz für die berechnung mittels rekursion und eines cache-arrays gefunden, nur iterativ über ein array...
 

JStein52

Top Contributor
Du bist nicht blind. Der Link hat mit cache nichts zu tun, und das ist ja dein Problem. Ich wage mal die These du musst da andeers ran gehen. Deine Rekursion (und so macht man das üblicherweise ohne Cache ) rechnet ja von grösseren n's zu kleineren. Da wird der Cache doch nie gefüllt sein. Du sparst dir sozusagen nur die letzten 3 Aufrufe und deshalb 2n-3 !! Musst du hier nicht von kleineren zu grösseren n's gehen ?
 

mseep

Mitglied
Du bist nicht blind. Der Link hat mit cache nichts zu tun, und das ist ja dein Problem. Ich wage mal die These du musst da andeers ran gehen. Deine Rekursion (und so macht man das üblicherweise ohne Cache ) rechnet ja von grösseren n's zu kleineren. Da wird der Cache doch nie gefüllt sein. Du sparst dir sozusagen nur die letzten 3 Aufrufe und deshalb 2n-3 !! Musst du hier nicht von kleineren zu grösseren n's gehen ?

na mit der antwort kann ich was anfangen, dank dir! ich mach mir mal meine gedanken dazu und versuchs umzusetzen :)
 
K

kneitzel

Gast
Hi Klaus,

das Problem vom TE ist ja nicht die eigentliche Berechnung der Fibonacci Zahl sondern die Reduzierung der rekursiven Aufrufe. Das wird da nicht behandelt. In dem Thread wird nur kurz dargestellt, dass diverse Fibonacci-Zahlen mehrfach berechnet werden (am Beispiel der fib(5).). Bezüglich der Problematik dürfte Joose einen Fehler gefunden haben. Aber die ganze Logik scheint mir noch zu komplex zu sein.

Fib(n) = fib(n-1) + fib(n-2)
Also ist fib(n-1) = fib(n-2) + fib(n-3)
Das bedeutet, dass bei der Berechnung von fib(n-1) auch fib(n-2) berechnet werden muss.

Somit gilt, dass wenn fib(n-1) bekannt ist, dann ist auch fib(n-2) bekannt. Hier gibt es am Anfang nur eine einzige Ausnahme: Es wird nur das erste Feld initialisiert und dann bei der ersten Berechnung bräuchte man zwei Werte. Das kann man mit einer zusätzlichen IF Anweisung lösen, aber ich würde da einfach ein Array-Feld des Caches mehr verbrauchen. Ich würde fib(n) in cache[n] speichern. Dann würde der cache initialisiert mit cache[0] = 0; cache[1] = 1;

Das führt dann zu einem sehr einfachen Code:
- Wenn cache[n-1] unbekannt, dann cache[n-1] = fib(n-1) -> Rekursiver Aufruf.
- cache[n] = cache[n-1]+cache[n-2]
- cache[n] zurück geben.

Desweiteren fällt mir auf, dass die Initialisierung des caches unschön ist. Hier würde ich objektorientiert heran gehen und das in eine eigene Klasse tun. Der Konstruktor würde dann die ersten zwei Felder initialisieren. Bei fin(1000) werden die ersten Felder sonst tausend mal gesetzt was ja nicht sein muss.

Viele Grüße,

Konrad
 

mseep

Mitglied
Hi Klaus,

das Problem vom TE ist ja nicht die eigentliche Berechnung der Fibonacci Zahl sondern die Reduzierung der rekursiven Aufrufe. Das wird da nicht behandelt. In dem Thread wird nur kurz dargestellt, dass diverse Fibonacci-Zahlen mehrfach berechnet werden (am Beispiel der fib(5).). Bezüglich der Problematik dürfte Joose einen Fehler gefunden haben. Aber die ganze Logik scheint mir noch zu komplex zu sein.

Fib(n) = fib(n-1) + fib(n-2)
Also ist fib(n-1) = fib(n-2) + fib(n-3)
Das bedeutet, dass bei der Berechnung von fib(n-1) auch fib(n-2) berechnet werden muss.

Somit gilt, dass wenn fib(n-1) bekannt ist, dann ist auch fib(n-2) bekannt. Hier gibt es am Anfang nur eine einzige Ausnahme: Es wird nur das erste Feld initialisiert und dann bei der ersten Berechnung bräuchte man zwei Werte. Das kann man mit einer zusätzlichen IF Anweisung lösen, aber ich würde da einfach ein Array-Feld des Caches mehr verbrauchen. Ich würde fib(n) in cache[n] speichern. Dann würde der cache initialisiert mit cache[0] = 0; cache[1] = 1;

Das führt dann zu einem sehr einfachen Code:
- Wenn cache[n-1] unbekannt, dann cache[n-1] = fib(n-1) -> Rekursiver Aufruf.
- cache[n] = cache[n-1]+cache[n-2]
- cache[n] zurück geben.

Desweiteren fällt mir auf, dass die Initialisierung des caches unschön ist. Hier würde ich objektorientiert heran gehen und das in eine eigene Klasse tun. Der Konstruktor würde dann die ersten zwei Felder initialisieren. Bei fin(1000) werden die ersten Felder sonst tausend mal gesetzt was ja nicht sein muss.

Viele Grüße,

Konrad

das blöde ist nur, dass cache[n] nicht existiert, da cache[] ja nur mit n stellen deklariert wird. die main war in der aufgabe vorgegeben und darf nicht verändert werden. abgegeben werden darf nur EINE .java-datei, also fällt die objektorientierte umsetzung auch flach, alles ein wenig verzwickt :D
 
K

kneitzel

Gast
Ok, das mit dem objektorientierten Ansatz ist ja auch nicht so wild. Wie die Werte gespeichert werden ist ja nicht ganz so wichtig. Wenn man fib(0) nicht im cache speichern kann, dann kann man das ja über ein einfache if abhandeln.

Man muss dann halt:
- zwei cache Werte sichern.
- Erst prüfen, ob der cache für die gewünsche Zahl schon gefüllt ist.
- Dann die eigentliche Lösung wie von mir beschrieben.

Und damit nicht unnötig Prüfungen stattfinden kann man sogar den Code noch auf Zwei Funktionen aufteilen. Deine fib Funktion hat dann nur noch reine Initialisierung und Prüfung des Caches und die Rekursion mit Berechnungen ist dann komplett in einer (privaten) Funktion BerechneFibonacci oder so. (Was aber evtl. von der Aufgabenstellung auch ausgeschlossen ist.)

Konrad
 

klauskarambulut

Bekanntes Mitglied
Java:
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author klauskarambulut
 */
public class Fibonacci {

    public static void main(String[] args) {
        for (int i = 10; i >= 0; i--) {
            System.out.println("Fib " + i + ":  " + fib(i));
        }
    }

    private static final Map<Integer, Long> fibs = new HashMap<>();

    private static long fib(int i) {

        return fibs.computeIfAbsent(i, t -> {
            System.out.println("Calculation of " + i);
            return (t <= 1) ? 1l : fib(t - 1) + fib(t - 2);

        });
    }
}

Ist doch alles schon im Standard drin
 
K

kneitzel

Gast
Hallo klauskrambulut,

das erfüllt aber nicht die Anforderungen des TE. Es war explizit verlangt, die Anzahl der fib Aufrufe zu minimieren und das ist bei Deiner Implementation nicht gegeben. Wenn Du fib(t-1) berechnest dann kannst Du im Anschluss direkt fib(t-2) aus dem Cache nehmen. Hier zwei fib Aufrufe zu verwenden ist einfach nicht sinnvoll und sorgt für deutlich mehr Aufrufe von fib.

Konrad
 

JStein52

Top Contributor
Aber so passt es:

Java:
  private static int aufrufe = 0;
  private static int fib(int n, int[] cache) {
  aufrufe++;


  if(n <= 0){
  return 0;
  }

  fib(n-1,cache);
  if (n==1){
  cache[0] = 1;
  }
  else if (n==2) {
  cache[1] = 1;
  }
  else {
  cache[n-1]= cache[n-3] + cache[n-2];
  }
  return cache[n-1];
  }

Wichtig ist dass man zuerst in die Rekursion absteigt damit der Cache von unten gefüllt wird.

Ergebnis:
run:
fib(11) = 89 (Aufrufe = 12)
BUILD SUCCESSFUL (total time: 1 second)

Edit: die letzte Abfrage kann man vereinfachen, habe ich inzwischen schon im Code oben gemacht !
 
Zuletzt bearbeitet:
K

kneitzel

Gast
Also wenn man hier jetzt eine Musterlösung posten sollte, dann wäre mein Favorit:

Java:
import java.util.*;

public class ZahlenMuster {

  private static int aufrufe = 0;

  private static int fib(int n, int[] cache) {
    aufrufe++;

    if(n <= 0){
      return 0;
    }

    // switch statt der vielen ifs
    switch (n)
    {
      case 1:
      case 2:
        // Hier finde ich die Lösung interessant, dass der Cache nur einmal gesetzt wird. Gefiel mir gut bei JStein52
        cache[0] = 1;
        cache[1] = 1;
        return 1;

      default:
        if (cache[n-2] == 0)
          fib(n-1,cache); // Diese Stelle gefiel mir eigentlich nicht - die Rückgabe wird ignoriert. Aber das erspart uns ein mehrfachen code.

        return cache[n-1]= cache[n-2] + cache[n-3]; // Sollte man evtl. in zwei Zeilen machen. Return mit einer Zuweisung ist evtl. in den Augen vieler nicht "sauber".
      }
    }

    public static void main(String[] args) {
      int[] cache = new int[20];
      int fib20 = fib(20, cache);
      for (int i = 0; i<20; i++) {
        System.out.println(cache[i]);
      }
      System.out.println(aufrufe);
    }
}

Hat im Vergleich zu der Lösung von JStein52 zwei Aufrufe weniger (19 statt 21 bei Berechnung von fib(20)).
 

JStein52

Top Contributor
@kneitzel : Ist das gleiche aber die Abfrage im default-Zweig kannst du dir schenken. Das entspricht meinem letzten else.
Und du hast nur zwei Aufrufe weniger weil du es anders initialisierst. Daqs hatte ich auch zuerst aber ich dachte der TE wollte n+1 Aufrufe :):)
 
K

kneitzel

Gast
Jo, stimmt. Habe wohl nicht gut genug hingesehen. Aber hast mit Deiner Sicht natürlich Recht. Die Initialisierung im if von Dir fand ich übrigens eine sehr gute Idee. Das hatte ich zuerst so nicht gesehen.

Viele Grüße,

Konrad
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
jhCDtGVjcZGcfzug Fibonacci Zahlen rekursiv und iterativ Java Basics - Anfänger-Themen 21
S Fibonacci Zahlen rekursiv Java Basics - Anfänger-Themen 1
J Fibonacci -Folge rekursiv berechnen Java Basics - Anfänger-Themen 18
B Fibonacci Zahlen rekursiv Array Java Basics - Anfänger-Themen 12
Z Fibonacci rekursiv meine Erklärung stimmt so? Java Basics - Anfänger-Themen 2
M Fibonacci-Linear und Rekursiv Java Basics - Anfänger-Themen 14
S Abwandlung der Fibonacci Folge Java Basics - Anfänger-Themen 3
T Fibonacci mit einer Hilfsmethode berechnen Java Basics - Anfänger-Themen 10
123456789sssssaaaa Which is the best way to Print Fibonacci Series in Java? Java Basics - Anfänger-Themen 3
J Fibonacci-Reihe Java Basics - Anfänger-Themen 12
G Fibonacci Zahlenreihe Fehler Java Basics - Anfänger-Themen 4
D Fibonacci overflow integer Java Basics - Anfänger-Themen 8
B Fibonacci Zahlen dynamische Programmierung Java Basics - Anfänger-Themen 7
N Dynamisches Programmieren/Fibonacci Java Basics - Anfänger-Themen 1
V Fibonacci Folge Java Basics - Anfänger-Themen 4
A Fibonacci Zahlen Java Basics - Anfänger-Themen 1
M Methoden Fibonacci-Folge Java Basics - Anfänger-Themen 6
P Fibonacci -Verallgemeintert Java Basics - Anfänger-Themen 2
K Methoden Fibonacci in Array mit rekursiver Methoden Java Basics - Anfänger-Themen 19
T Stack Overflow - Rekursive Fibonacci Java Basics - Anfänger-Themen 10
K Fibonacci Zahlen Java Basics - Anfänger-Themen 3
M Fibonacci-Folge mit while-Schleife Java Basics - Anfänger-Themen 4
P fibonacci - do while Statement Logik Fehler Java Basics - Anfänger-Themen 5
A Fibonacci-numbers Java Basics - Anfänger-Themen 9
K Rekursion Fibonacci Java Basics - Anfänger-Themen 3
J Fibonacci Zahlen berechnen Java Basics - Anfänger-Themen 3
Z Fibonacci Array Erklärung Java Basics - Anfänger-Themen 5
A Gerade Terme der Fibonacci-Folge aufsummieren Java Basics - Anfänger-Themen 12
M Fibonacci, Fakultaet, GGT Java Basics - Anfänger-Themen 9
C Fibonacci Zahlen Java Basics - Anfänger-Themen 7
J Ausgabe der fibonacci Zahlen Java Basics - Anfänger-Themen 4
S Fibonacci Folge Java Basics - Anfänger-Themen 34
D Fibonacci Java Basics - Anfänger-Themen 11
W Fibonacci Zahlenberechnung Java Basics - Anfänger-Themen 9
X Fibonacci mit durchschnittlicher Zeit Java Basics - Anfänger-Themen 5
I Fibonacci-Folge , direkter Weg. Java Basics - Anfänger-Themen 5
G Fibonacci Algorithmus Java Basics - Anfänger-Themen 22
0 Fibonacci Zahlen seeeehr schnell berechnen Java Basics - Anfänger-Themen 9
S Fibonacci Rückrechnung! Java Basics - Anfänger-Themen 5
K Fibonacci Zahlen Java Basics - Anfänger-Themen 2
K Programmieren von den ersten 70 Fibonacci-Zahlen Java Basics - Anfänger-Themen 2
G fibonacci was stimmt an meinem code nicht? Java Basics - Anfänger-Themen 2
S Fibonacci Zahlenvergeich Java Basics - Anfänger-Themen 6
G Iterativer Algorithmus zur Berechnung der Fibonacci Zahlen Java Basics - Anfänger-Themen 1
P Fibonacci-Zahlen Java Basics - Anfänger-Themen 6
H Passwort Brute Force rekursiv Java Basics - Anfänger-Themen 7
1 Array rekursiv durchlaufen Java Basics - Anfänger-Themen 8
E Rekursiv Objekte erzeugen - geht das? Java Basics - Anfänger-Themen 2
Cassy3 Binäre Bäume Rekursiv durchlaufen und bestimmte Elemente Zählen Java Basics - Anfänger-Themen 6
R0m1lly Kombinationen aus int array rekursiv Java Basics - Anfänger-Themen 2
L Rekursiv gegebenes Passwort herausfinden. Java Basics - Anfänger-Themen 2
P9cman Char Index rekursiv finden Java Basics - Anfänger-Themen 4
B Methoden Rekursiv festellen, ob eine Zahl gerade-oft vorkommt oder nicht Java Basics - Anfänger-Themen 4
S Methoden Methodenaufruf rekursiv zählen Java Basics - Anfänger-Themen 4
B Array nach Wert prüfen rekursiv Java Basics - Anfänger-Themen 5
sashady Zahlen rekursiv zerlegen und Ziffern addieren Java Basics - Anfänger-Themen 38
H Binominalkoeffizient tail-rekursiv in java darstellen Java Basics - Anfänger-Themen 0
GAZ Tribonacci Folge Rekursiv Java Basics - Anfänger-Themen 11
G Primzahlen von Rekursiv nach Iterativ Java Basics - Anfänger-Themen 6
A Ackermmanfunktion rekursiv Java Basics - Anfänger-Themen 4
A Binärbaum rekursiv durchsuchen und Referenz zurückgeben Java Basics - Anfänger-Themen 4
H Rekursiv Methode ausführen bei Kindern Java Basics - Anfänger-Themen 12
G Methode Rekursiv umschreiben Java Basics - Anfänger-Themen 8
L Jede zweite Ziffer entfernen (rekursiv) Java Basics - Anfänger-Themen 6
J Dateien in Verzeichnissen rekursiv auflisten wirft Exception Java Basics - Anfänger-Themen 4
D Pentagonale Nummern in Rekursiv Java Basics - Anfänger-Themen 14
O Enum Array Rekursiv abarbeiten Java Basics - Anfänger-Themen 44
E Weg-Suche-Problem rekursiv Java Basics - Anfänger-Themen 12
O Primzahl rekursiv mit einem Wert ohne i, wie? Java Basics - Anfänger-Themen 6
E Erste Schritte Potenz Negativ (rekursiv) Java Basics - Anfänger-Themen 2
O Rekursiv aufrufen Java Basics - Anfänger-Themen 2
F In List Rekursiv suchen Java Basics - Anfänger-Themen 12
F Iterativ in Rekursiv Java Basics - Anfänger-Themen 2
L Rekursiv zwei Strings vergleichen Java Basics - Anfänger-Themen 3
B Fakultätsfunktion Rekursiv Berechnen aber mit Array Java Basics - Anfänger-Themen 10
B Wie kann ich Linien rekursiv zeichnen? Java Basics - Anfänger-Themen 4
kilopack15 Sin(x) rekursiv lösen Java Basics - Anfänger-Themen 17
T Rekursiv Tiefe eines binären Suchbaums ermitteln Java Basics - Anfänger-Themen 22
P Methoden Arrays.AsList kleinste Zahl ausgeben Rekursiv Java Basics - Anfänger-Themen 9
W A hoch N Rekursiv Java Basics - Anfänger-Themen 3
K Rechtecke rekursiv zeichnen Java Basics - Anfänger-Themen 20
V Quadrate rekursiv zeichnen Java Basics - Anfänger-Themen 7
E Binärbaum - von rekursiv zu iterativ Java Basics - Anfänger-Themen 10
Y Rekursiv Palindrom herausfinden Java Basics - Anfänger-Themen 5
M String rekursiv Spiegeln mit Originalwort davor Java Basics - Anfänger-Themen 3
K Türme von Hanoi - Rekursiv. Java Basics - Anfänger-Themen 1
T MergeSort rekursiv programmieren Java Basics - Anfänger-Themen 8
M Zahlenpyramide rekursiv programmieren Java Basics - Anfänger-Themen 7
hello_autumn Potenz selber berechnen, Rekursiv. Java Basics - Anfänger-Themen 6
V Text wüerfeln-Rekursiv Java Basics - Anfänger-Themen 4
J Baum rekursiv durchlaufen Java Basics - Anfänger-Themen 2
D Münzverteilung Möglichkeiten | Rekursiv Java Basics - Anfänger-Themen 3
R Hanoi rekursiv lösen Problem Java Basics - Anfänger-Themen 1
D Rekursiv Kombinationen ausgeben klappt nur bei einer Wiederholung Java Basics - Anfänger-Themen 4
shiroX OOP String rekursiv zurückgeben Java Basics - Anfänger-Themen 6
S java rekursiv iterativ hilfee :s Java Basics - Anfänger-Themen 5
E Erste Schritte Pi, rekursiv Java Basics - Anfänger-Themen 6
A Frage Methode ggt Rekursiv Java Basics - Anfänger-Themen 5
E Hanoi-Varianten rekursiv Java Basics - Anfänger-Themen 2
P Hanoi rekursiv zu iterativ umbauen Java Basics - Anfänger-Themen 20

Ähnliche Java Themen

Neue Themen


Oben