Qualifikationsphase Q1 · Themenfeld Q1.3

Q1.3 – Rekursion als Modellierungsstrategie

Algorithmen systematisch vergleichen: iterativ, rekursiv und effizient

In Q1.2 wurden Algorithmen systematisch als endliche, eindeutige, ausführbare und allgemeingültige Verfahren eingeführt. Dort standen iterative Such- und Sortierverfahren als gemeinsame Referenzmodelle im Zentrum.

Q1.3 setzt daran problemorientiert an: In Q1.2 lag der Schwerpunkt auf dem Ablauf eines Algorithmus (Schritt für Schritt, Schleife für Schleife). Jetzt rückt die Struktur eines Problems in den Fokus: Wie lässt sich eine Aufgabe in Teilprobleme zerlegen, sodass aus deren Lösungen die Gesamtlösung entsteht?

Q1.3 erweitert damit die Grundlage aus Q1.2: Dasselbe Problem kann iterativ oder rekursiv modelliert werden. Rekursion, Teile-und-herrsche und Effizienzreflexion werden als zusammenhängende Vertiefung entwickelt, bei der das Entstehen von Teilproblemen explizit sichtbar gemacht wird.

Kerncurriculum
Kerncurriculum kompakt
Anforderungen nach Kursniveau
Grundlegendes Niveau (Grundkurs und Leistungskurs)
Erhöhtes Niveau (Leistungskurs)
Rückbezug
Rückbezug auf Q1.2: iterative Referenzmodelle
Iterative Grundlagen aus Q1.2 als Ausgangspunkt für Rekursion und Modellvergleich

Als Referenz dienen bekannte Suchalgorithmen und Sortieralgorithmen: lineare Suche (sequentielles Durchlaufen) und Sortieren durch Einfügen (sukzessive Einordnung). Beide arbeiten primär mit Schleife, Index/Zähler und lokalem Zustandsupdate.

Lineare Suche (iterative Referenz)

int linearSearch(int[] a, int key) {
    for (int i = 0; i < a.length; i++) {
        if (a[i] == key) return i;
    }
    return -1;
}

Sortieren durch Einfügen (iterative Referenz)

void insertionSort(int[] a) {
    for (int i = 1; i < a.length; i++) {
        int x = a[i];
        int j = i - 1;
        while (j >= 0 && a[j] > x) {
            a[j + 1] = a[j];
            j--;
        }
        a[j + 1] = x;
    }
}
Rekursion
Rekursion als neues Strukturprinzip
Selbstaufruf, Rekursionsanker, Rekursionsschritt, Parameterübergabe
Rekursion und rekursiver Algorithmus
Rekursion führt ein Problem auf kleinere Teilprobleme derselben Art zurück. Ein rekursiver Algorithmus setzt das über Selbstaufrufe um, bis eine Terminationsbedingung erreicht ist.
Kriterium Leitfrage zur Modellierung Mini-Beispiel
Teilproblemstruktur Kann ich das Gesamtproblem in kleinere Probleme desselben Typs zerlegen? Binäre Suche: nur ein kleineres Intervall bleibt übrig.
Selbstähnlichkeit Wird in jedem Schritt wieder dieselbe Regel angewendet? Quicksort: „Pivot wählen, trennen, Teilfolgen sortieren“ auf jeder Ebene.
Basisfall Wann ist das Teilproblem so klein, dass es direkt lösbar ist? Quicksort: leere Folge oder ein Element ist bereits sortiert.
Kombination Wie wird aus Teilresultaten wieder die Gesamtlösung? Fakultät: n * fakultaet(n-1), Quicksort: links + Pivot + rechts.

Beispiel: Fakultät als einfache Rekursion

long fakultaet(int n) {
    if (n <= 1) return 1;      // Rekursionsanker
    return n * fakultaet(n - 1); // Rekursionsschritt
}

Aufrufverlauf (fakultaet(4))

Diese Darstellung ist eine Visualisierung rekursiver Abläufe: Die Aufrufkette wächst bis zum Basisfall und läuft dann mit Rückgabewerten zurück. Jeder Aufruf wird auf dem Stack gehalten; die Rekursionstiefe beeinflusst daher den Speicherbedarf.

Einfache und mehrfache Rekursion
Einfache Rekursion erzeugt pro Aufruf höchstens einen weiteren Rekursionsaufruf (z. B. Fakultät, rekursive lineare Suche). Mehrfache Rekursion erzeugt mehrere Folgeaufrufe, etwa bei Quicksort mit linkem und rechtem Teilproblem.

Weitere Rekursionsbeispiele

Rekursive lineare Suche
int linearSearchRec(int[] a, int key, int i) {
    if (i >= a.length) return -1;
    if (a[i] == key) return i;
    return linearSearchRec(a, key, i + 1);
}

Teilproblem: „Suche ab Index i“.

Rekursive binäre Suche
int binarySearchRec(int[] a, int key, int l, int r) {
    if (l > r) return -1;
    int m = (l + r) / 2;
    if (a[m] == key) return m;
    if (key < a[m]) return binarySearchRec(a, key, l, m - 1);
    return binarySearchRec(a, key, m + 1, r);
}

Teilproblem: nur linke oder rechte Hälfte.

Einfache rekursive Summe
int summeBis(int n) {
    if (n <= 0) return 0;
    return n + summeBis(n - 1);
}

Rekursion ist damit nicht auf ein Einzelbeispiel beschränkt, sondern ein allgemeines Muster.

Stack konkret: Aufruf- und Rückgabephase bei summeBis(4)

Aufrufkette: summeBis(4) → summeBis(3) → summeBis(2) → summeBis(1) → summeBis(0)
Anker: summeBis(0) = 0
Rückgabe: summeBis(1) = 1 + 0 = 1
Rückgabe: summeBis(2) = 2 + 1 = 3
Rückgabe: summeBis(3) = 3 + 3 = 6
Rückgabe: summeBis(4) = 4 + 6 = 10
Vergleich
Zentrale Gegenüberstellung: iterativ vs. rekursiv
Steuerung, Zustandsverwaltung und Effizienzfolgen systematisch gegenüberstellen

Vergleich A: Binäre Suche

Iterative Darstellung
int binarySearchIter(int[] a, int key) {
    int l = 0, r = a.length - 1;
    while (l <= r) {
        int m = (l + r) / 2;
        if (a[m] == key) return m;
        if (key < a[m]) r = m - 1;
        else l = m + 1;
    }
    return -1;
}
Rekursive Darstellung
int binarySearchRec(int[] a, int key, int l, int r) {
    if (l > r) return -1;
    int m = (l + r) / 2;
    if (a[m] == key) return m;
    if (key < a[m]) return binarySearchRec(a, key, l, m - 1);
    return binarySearchRec(a, key, m + 1, r);
}
Intervallfolge iterativ (gleiche Eingabe)
Start: l=0, r=15
Schleife 1: m=7 → rechte Hälfte ⇒ l=8, r=15
Schleife 2: m=11 → rechte Hälfte ⇒ l=12, r=15
Schleife 3: m=13 → linke Hälfte ⇒ l=12, r=12
Schleife 4: m=12 → Treffer oder Abbruch
Intervallfolge rekursiv (gleiche Eingabe)
binarySearchRec(a,key,0,15)
→ Teilproblem entsteht: binarySearchRec(a,key,8,15)
→ Teilproblem entsteht: binarySearchRec(a,key,12,15)
→ Teilproblem entsteht: binarySearchRec(a,key,12,12)
→ Basisfall/Treffer: Rückgabe in umgekehrter Reihenfolge
Aspekt Iteration Rekursion
Steuerung Explizit über Schleifenbedingungen. Implizit über Selbstaufrufe + Anker.
Zustand Variablen wie l, r, i werden fortgeschrieben. Zustand steckt in Parametern jedes Aufrufs.
Struktur Linearer Kontrollfluss im selben Block. Hierarchische Zerlegung in Teilprobleme.
Denkweise „Wiederhole, bis Bedingung verletzt.“ „Löse kleineres Teilproblem und kombiniere.“
Speicher Konstanter Zusatzspeicher (typisch). Zusätzlicher Aufrufstack pro Rekursionsstufe.
Konkretes Beispiel (binäre Suche) Ein Schleifendurchlauf ersetzt den vorherigen Zustand (l,r). Jeder Aufruf erzeugt einen neuen Zustand als eigenes Teilproblem.
Rekursion versus Iteration
Rekursion und Iteration sind zwei verschiedene Wege für wiederholte Problemlösungen: Iteration steuert Wiederholung über Schleifen, Rekursion über Aufrufe auf kleineren Teilproblemen. Welche Variante günstiger ist, hängt von Problemstruktur, Lesbarkeit und Aufwand ab.

Konkreter Vergleich (binäre Suche): Beide Varianten halbieren denselben Suchraum. Iterativ ändern sich nur l/r in einer Schleife, rekursiv entstehen nacheinander Aufrufe wie (l,r)=(0,15)→(8,15)→(12,15).

Vergleich B: Sortierstrategie

Problem / Idee Iteratives Referenzmodell Rekursives Modell Fachliche Auswertung
Unsortierte Liste ordnen Insertion Sort: baue von links einen sortierten Bereich auf;
jedes Element wird durch Vergleiche eingeordnet.
Quicksort: teile per Pivot in „kleiner“ und „größer“, sortiere Teilfolgen rekursiv, füge logisch zusammen. Insertion ist lokal einfach, bei großen Datenmengen oft langsam. Quicksort nutzt Teile-und-herrsche, ist typischerweise deutlich schneller, kann im ungünstigen Fall aber stark abfallen.
Insertion: struktogrammnahe Blockfolge
FOR i = 1 bis n-1
├─ x = a[i]
├─ WHILE a[j] > x: verschiebe
└─ x einfügen
Quicksort: vollständiges Beispiel (rekursiv)
Ausgangsliste: [7 2 9 4 1 8 3]
Ebene 0: Pivot 4 → [2 1 3] |4| [7 9 8]
Teilprobleme entstehen: sort([2 1 3]) und sort([7 9 8])
Ebene 1 links: Pivot 1 → [] |1| [2 3]
Ebene 1 rechts: Pivot 8 → [7] |8| [9]
Ebene 2 links-rechts: Pivot 2 → [] |2| [3]
Basisfälle: [] , [3] , [7] , [9]
Kombination: [1 2 3] |4| [7 8 9]
Ergebnis: [1 2 3 4 7 8 9]
Quicksort in Java (Teilproblem + Rekursion explizit)
void quicksort(int[] a, int l, int r) {
    if (l >= r) return;                     // Basisfall
    int p = partition(a, l, r);             // Zerlegung um Pivot
    quicksort(a, l, p - 1);                 // Teilproblem links
    quicksort(a, p + 1, r);                 // Teilproblem rechts
}
Effizienz
Effizienzgedanke fachlich abrunden
Schrittzahlen, Wachstumsverhalten und Speicheraspekt sichtbar machen

Der Effizienzgedanke wurde in Q1.2 eingeführt und wird hier präzisiert: Nicht nur „funktioniert?“, sondern wie gut skaliert die Modellierungsentscheidung? Relevante Indikatoren sind Anzahl von Vergleichen, notwendige Schritte und zusätzlicher Speicher (z. B. Aufrufstack).

Verfahren Qualitative Laufzeittendenz Typischer Effizienzeindruck
Lineare Suche Wachstum proportional zur Listengröße (linear) bei großen Datenmengen schnell spürbar langsamer
Binäre Suche Suchraum halbiert sich pro Schritt (logarithmisch) auch bei großen Datenmengen sehr wenige Prüfungen
Sortieren durch Einfügen häufig viele Vergleiche/Verschiebungen (quadratische Tendenz) für kleine/nahezu sortierte Listen gut, sonst aufwendig
Quicksort guter Fall: n log n, schlechter Fall: starke Praxisleistung bei ausgeglichener Teilproblemstruktur, kritisch bei stark einseitiger Zerlegung
Warum guter Fall n log n?
  • Jede Ebene verarbeitet insgesamt etwa n Elemente (Partitionierung).
  • Bei ausgewogener Pivot-Wahl hat der Rekursionsbaum etwa log n Ebenen.
  • Gesamt: n Arbeit pro Ebene × log n Ebenen.
Warum schlechter Fall ?
  • Pivot trennt extrem unausgewogen (z. B. schon sortierte Liste + schlechtes Pivot).
  • Teilprobleme sind dann fast n-1 und 0.
  • Rekursionsbaum wird tief (nahezu n Ebenen) bei weiterhin hoher Arbeit pro Ebene.
Teile und herrsche
Teile-und-herrsche als Brücke
Übergeordnetes Prinzip hinter Binärsuche und Quicksort
Teile-und-herrsche
Das Prinzip „teile und herrsche“ zerlegt ein Problem in kleinere Teilprobleme, löst diese und führt die Teillösungen zusammen.

1) Zerlegen

Problem in kleinere Teilprobleme aufteilen (Intervall halbieren, Pivot-trennen).

2) Bearbeiten

Teilprobleme iterativ oder rekursiv lösen; bei Rekursion mit klarer Termination.

3) Zusammenführen

Teilresultate zu einer Gesamtlösung verbinden (Trefferentscheidung, sortierte Folge).

Rekursion ist damit nicht nur Syntax, sondern ein tragfähiges Modell für strukturierte Problemlösung in der Algorithmik.

Präzisierung: Bei der binären Suche geschieht Teile-und-herrsche als wiederholte Halbierung des Intervalls; bei Quicksort als Zerlegung um ein Pivot in zwei Teilfolgen. Wichtig: Nicht jede Rekursion ist automatisch Divide-and-Conquer (z. B. Fakultät verkleinert nur linear).

LK-Anschluss: Backtracking
Backtracking ist ein rekursionsnahes Suchverfahren: Lösungswege werden schrittweise aufgebaut und bei einer Sackgasse wieder zurückgenommen. Typisch ist die Suche im Entscheidungs- oder Zustandsraum.
Tool-Vergleich
Tool-gestützte Vergleichsanalyse
Iterative und rekursive Varianten als beobachtbarer Modellvergleich

Das Werkzeug Such- und Sortieralgorithmen visualisieren wird in Q1.3 als Vergleichsinstrument genutzt. Im Unterschied zu Q1.2 geht es hier nicht nur um Ablaufverständnis, sondern um die begründete Gegenüberstellung von Modellierungsentscheidungen.

Leitfrage im Tool
Was zeigt das Tool konkret (Vergleichszahl, Verlauf, Teilproblemfolge) – und welche Unterschiede zwischen iterativer und rekursiver Variante lassen sich daraus begründen?
  • Vergleiche iterative und rekursive Binärsuche bei identischer Datenbasis.
  • Nutze Insertion Sort (iterativ) und Quicksort (rekursiv), um Teile-und-herrsche zu reflektieren.
  • Dokumentiere Kurvenverläufe der Vergleichszahlen und beziehe Speicheraspekte (Aufrufstack) ein.

Beobachtungsschwerpunkt: gleiche Eingabegröße wählen, dann Verlauf der Vergleichsanzahl über mehrere Läufe kontrastieren und begründen, warum sich die Kurven bei Halbierung, linearer Prüfung oder rekursiver Teilproblemstruktur unterschiedlich entwickeln.

Rückbezug: Die in Q1.2 eingeführten Metriken werden hier als Argumentationsgrundlage für Modellnähe, Lesbarkeit und Effizienzfolgen verwendet.

Reflexion
Reflexion: begründete Verfahrenswahl
analysieren · vergleichen · beurteilen · begründen
  • Iteration ist oft naheliegend, wenn ein Ablauf linear und zustandsnah über Schleifen steuerbar ist.
  • Rekursion ist besonders anschlussfähig, wenn die Problemstruktur selbst hierarchisch oder teilproblemorientiert ist.
  • Rekursiv ist nicht automatisch besser: Lesbarkeit kann steigen, aber Stackkosten und ungünstige Fälle bleiben zu prüfen.
  • Effizienz ist ein fachliches Kernkriterium, weil informatische Lösungen unter realen Datenmengen tragfähig sein müssen.

Anschluss: Diese Vergleichsperspektive baut auf den Grundlagen aus Q1.2 auf und bereitet direkt auf vertiefte Laufzeit- und Komplexitätsbetrachtungen der Qualifikationsphase vor.