Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung Nächste Überarbeitung | Vorherige Überarbeitung | ||
faecher:informatik:oberstufe:algorithmen:rekursion:uebungen03:start [05.02.2023 16:55] – Frank Schiebel | faecher:informatik:oberstufe:algorithmen:rekursion:uebungen03:start [18.02.2025 06:45] (aktuell) – Frank Schiebel | ||
---|---|---|---|
Zeile 3: | Zeile 3: | ||
{{: | {{: | ||
=== (A1) Pascalsches Dreieck === | === (A1) Pascalsches Dreieck === | ||
+ | {{ : | ||
+ | Beim Pascalschen Dreieck werden die jeweils oberhalb liegenden Felder addiert und ergeben das darunter liegende Feld, wie in der Animation rechts zu sehen ist. | ||
+ | |||
+ | Man kann eine rekursive Funktion implementieren, | ||
+ | |||
+ | (A) Implementiere '' | ||
+ | |||
+ | ++++ Tipp 1 | Ein mögliches Codegerüst könnte so aussehen: | ||
+ | |||
+ | <code java> | ||
+ | public int pascal(int z, int s) | ||
+ | { | ||
+ | if ( ) { | ||
+ | | ||
+ | } else { | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ++++ | ||
+ | |||
+ | ++++ Tipp 2 | | ||
+ | |||
+ | * Der Basisfall tritt immer dann ein, wenn das Element in Zeile 0 oder 1 oder in Spalte 0 oder z ist. Dann wird 1 zurückgegeben. | ||
+ | * Im Rekursionsfalll wird '' | ||
+ | ++++ | ||
+ | |||
+ | ++++ Lösungsvorschlag | | ||
+ | |||
+ | <code java> | ||
+ | public int pascal(int z, int s) | ||
+ | { | ||
+ | if ( z==0 || s==0 || s==z ) { | ||
+ | return 1; | ||
+ | } else { | ||
+ | return pascal(z-1, s-1) + pascal(z-1, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ++++ | ||
+ | |||
+ | Die rekursiven Aufrufe können in einem **Aufruf-Baum** veranschaulicht werden, hier am Beispiel '' | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | |||
+ | (B) Zeichne den Aufrufbaum für den Aufruf '' | ||
---- | ---- | ||
Zeile 14: | Zeile 61: | ||
Die Fibonacci-Funktion (auch als Fibonacci-Folge bezeichnet) ist definiert als: | Die Fibonacci-Funktion (auch als Fibonacci-Folge bezeichnet) ist definiert als: | ||
- | {{: | + | {{: |
Zeile 30: | Zeile 77: | ||
(B) Stelle die ausgeführten Methodenaufrufe bei der Ausführung von '' | (B) Stelle die ausgeführten Methodenaufrufe bei der Ausführung von '' | ||
- | Baum dar. | + | Baum dar. Gibt es Aufrufe von '' |
- | (C) Begründe, warum die Anzahl der Methodenaufrufe für '' | + | ++++ Lösung | |
+ | {{ : | ||
+ | Die rot markierten Aufrufe finden mehr als einmal statt. | ||
+ | ++++ | ||
+ | |||
+ | (C) Begründe, warum die Anzahl der Methodenaufrufe für '' | ||
(D) Implementiere eine Methode '' | (D) Implementiere eine Methode '' | ||
+ | |||
+ | ---- | ||
+ | {{: | ||
+ | === (A3) Fibonacci dynamisch-rekursiv (LF) === | ||
+ | |||
+ | Bei manchen Problemen kann man Zeit sparen, indem man geeignete Zwischenergebnisse abspeichert und später wiederverwendet. Diese Technik wird als dynamische Programmierung oder Memoisation bezeichnet: | ||
+ | |||
+ | < | ||
+ | int[] cache; | ||
+ | |||
+ | fibDyn(n: int): int | ||
+ | wenn n ≤ 1: | ||
+ | gib n zurück | ||
+ | cache = Array vom Typ int und der Länge n+1 | ||
+ | cache[0] = 0; | ||
+ | cache[1] = 1; | ||
+ | wiederhole für i von 2 bis n: | ||
+ | cache[i] = -1; | ||
+ | gib lookup(n) zurück | ||
+ | | ||
+ | lookup(n: int): int | ||
+ | wenn cache[n] < 0: | ||
+ | cache[n] = lookup(n-1) + lookup(n-2); | ||
+ | gib cache[n] zurück | ||
+ | </ | ||
+ | |||
+ | (A) Die Methode '' | ||
+ | |||
+ | (B) Begründe, warum die dynamische Implementierung effizienter ist als die rekursive von oben. | ||
+ | |||
+ | |||
+ | ++++ Lösung A | | ||
+ | |||
+ | {{ : | ||
+ | ++++ | ||
+ | |||
+ | |||
+ | ++++ Lösung B | | ||
+ | Die ursprüngliche rekursive Implementation berechnet fast alle Funktionswerte mehrfach. Durch die Verwendung | ||
+ | des cache-Arrays wird ein einmal berechneter Wert direkt nachgeschlagen und eine Rekursion ist nicht | ||
+ | nötig. | ||
+ | ++++ |