MINT lernen

Abituraufgaben: Rekursive Aufrufe verfolgen

Zwei Aufgaben im Abiturformat — von Stammbäumen bis zu den Türmen von Hanoi.

Dein Fortschritt:
0 / 0 Aufgaben
1

Vorfahren im Stammbaum

AFB I–II

Ein Ahnenforschungsprogramm berechnet, wie viele Vorfahren eine Person in den letzten g Generationen höchstens hat: 2 Eltern, 4 Großeltern, 8 Urgroßeltern usw. Dazu gibt es zwei Methoden. Die zweite hat ein Kollege geschrieben.

Material: zwei Methoden
static int vorfahren(int g) {
    if (g == 0) {
        return 0;
    }
    return 2 + 2 * vorfahren(g - 1);
}
static int vorfahren2(int g) {
    if (g == 0) {
        return 0;
    }
    return 2 + vorfahren2(g - 1) + vorfahren2(g - 1);
}
  1. Stellen Sie den Aufrufstapel zu vorfahren(3) in dem Moment dar, in dem er am höchsten ist, und geben Sie die Rückgabewerte aller Aufrufe an. 4 BE
  2. Geben Sie für vorfahren(g) die Rekursionstiefe und die Anzahl der Aufrufe in Abhängigkeit von \(g\) an. 2 BE
  3. Zeichnen Sie den Aufrufbaum für vorfahren2(2) mit den Rückgabewerten. 4 BE
  4. Leiten Sie eine Formel für die Anzahl der Aufrufe von vorfahren2(g) her und vergleichen Sie beide Methoden. 5 BE

Insgesamt 15 BE

Hinweise

Hinweis zu Aufgabe a)
Beim höchsten Stand liegt der Aufruf mit der Abbruchbedingung oben.
Hinweis zu Aufgabe b)
Zählen Sie die Werte, die g nacheinander annimmt.
Hinweis zu Aufgabe c)
Jeder Aufruf mit \(g \ge 1\) hat zwei Kinder mit \(g - 1\).
Hinweis zu Aufgabe d)
Stellen Sie eine Gleichung \(C(g) = 1 + 2\,C(g-1)\) mit \(C(0) = 1\) auf und setzen Sie einige Werte ein.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)

Höchster Stand (unten der erste Aufruf):

EbeneAufrufZustandRückgabe
4 (oben)vorfahren(0)Abbruch0
3vorfahren(1)wartet auf 2 + 2 · vorfahren(0)2
2vorfahren(2)wartet auf 2 + 2 · vorfahren(1)6
1 (unten)vorfahren(3)wartet auf 2 + 2 · vorfahren(2)14

Rückgabewert von vorfahren(3): 14 (2 + 4 + 8).

Erwartungshorizont zu Aufgabe b)

Die Aufrufe laufen mit \(g, g-1, \dots, 0\): Rekursionstiefe \(g + 1\), Anzahl der Aufrufe ebenfalls \(g + 1\) (lineare Rekursion).

Erwartungshorizont zu Aufgabe c)
v2(2)→ 6v2(1)→ 2v2(1)→ 2v2(0)→ 0v2(0)→ 0v2(0)→ 0v2(0)→ 0

Sieben Aufrufe; Rückgabewerte 0 (Blätter), 2 + 0 + 0 = 2 und 2 + 2 + 2 = 6.

Erwartungshorizont zu Aufgabe d)

\(C(g) = 1 + 2\,C(g-1)\), \(C(0) = 1\): \(C(1) = 3\), \(C(2) = 7\), \(C(3) = 15\), allgemein \(C(g) = 2^{g+1} - 1\). Beide Methoden liefern dieselben Werte und haben dieselbe Rekursionstiefe \(g + 1\). vorfahren2 berechnet aber das Teilergebnis vorfahren2(g - 1) doppelt; die Zahl der Aufrufe wächst exponentiell statt linear. Für 30 Generationen sind es über zwei Milliarden Aufrufe statt 31 — die Methode des Kollegen ist ungeeignet.

2

Die Türme von Hanoi

AFB II–III

Beim Spiel „Türme von Hanoi“ liegen \(n\) unterschiedlich große Scheiben auf Stab A, die größte unten. Sie sollen auf Stab C umgesetzt werden; Stab B dient als Hilfe. Es darf immer nur die oberste Scheibe eines Stabes bewegt werden, und nie darf eine größere auf einer kleineren liegen. Die Methode hanoi gibt die nötigen Züge aus.

Material: Methode hanoi
static void hanoi(int n, char von, char hilf, char nach) {
    if (n == 0) {
        return;
    }
    hanoi(n - 1, von, nach, hilf);
    System.out.println(von + " -> " + nach);
    hanoi(n - 1, hilf, von, nach);
}
  1. Analysieren Sie den Aufruf hanoi(2, 'A', 'B', 'C'): Zeichnen Sie den Aufrufbaum und geben Sie die Ausgabe an. 5 BE
  2. Begründen Sie, dass hanoi für jedes \(n \ge 0\) terminiert. 2 BE
  3. Leiten Sie her, dass hanoi(n, …) genau \(2^n - 1\) Züge ausgibt. 4 BE
  4. Beurteilen Sie nach einer Legende die Aufgabe von Mönchen, 64 Scheiben mit einem Zug pro Sekunde umzusetzen: Scheitert das Vorhaben am Aufrufstapel oder an der Zeit? 4 BE

Insgesamt 15 BE

Hinweise

Hinweis zu Aufgabe a)
Der erste Selbstaufruf vertauscht die Rollen von nach und hilf, der zweite die von von und hilf. Die Ausgabe steht zwischen den beiden Aufrufen.
Hinweis zu Aufgabe b)
Welcher Parameter ändert sich bei jedem Selbstaufruf, und wohin läuft er?
Hinweis zu Aufgabe c)
Zählen Sie die Züge \(Z(n)\): zwei Teilaufgaben mit \(n - 1\) Scheiben plus ein Zug.
Hinweis zu Aufgabe d)
Unterscheiden Sie Rekursionstiefe und Anzahl der Züge.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)

Aufrufbaum: hanoi(2,A,B,C) ruft hanoi(1,A,C,B) und hanoi(1,B,A,C) auf; jeder davon ruft zweimal hanoi(0,…) auf, die sofort zurückkehren (7 Aufrufe).

hanoi(1,A,C,B) gibt A -> B aus, danach hanoi(2,…) selbst A -> C, danach hanoi(1,B,A,C) B -> C. Ausgabe:

A -> B
A -> C
B -> C
Erwartungshorizont zu Aufgabe b)

Jeder Selbstaufruf verkleinert \(n\) um 1. Von \(n \ge 0\) aus wird deshalb nach \(n\) Stufen \(n = 0\) erreicht, wo die Methode ohne Selbstaufruf endet. Da jeder Aufruf höchstens zwei weitere erzeugt, ist die Gesamtzahl der Aufrufe endlich.

Erwartungshorizont zu Aufgabe c)

\(Z(0) = 0\), \(Z(n) = 2\,Z(n-1) + 1\). Daraus: \(Z(1) = 1\), \(Z(2) = 3\), \(Z(3) = 7\). Gilt \(Z(n-1) = 2^{n-1} - 1\), so folgt \(Z(n) = 2(2^{n-1} - 1) + 1 = 2^n - 1\). Mit \(Z(0) = 2^0 - 1 = 0\) gilt die Formel für alle \(n \ge 0\).

Erwartungshorizont zu Aufgabe d)

Die Rekursionstiefe beträgt nur \(65\) (n = 64 bis 0) — der Aufrufstapel ist kein Problem. Die Zahl der Züge ist aber \(2^{64} - 1 \approx 1{,}8 \cdot 10^{19}\). Bei einem Zug pro Sekunde dauert das etwa \(1{,}8 \cdot 10^{19} : (3{,}16 \cdot 10^{7}) \approx 5{,}8 \cdot 10^{11}\) Jahre, rund das Vierzigfache des Alters des Universums. Das Vorhaben scheitert an der Zeit, nicht am Speicher; auch ein Computer mit einer Milliarde Züge pro Sekunde bräuchte fast 600 Jahre.