Zuletzt aktualisiert am 04.12.2025 5 Minuten Lesezeit

Rekursion

Rekursion ist eine Programmiertechnik, bei der sich eine Funktion oder Methode selbst aufruft, um ein Problem zu lösen. Das Grundprinzip besteht darin, ein komplexes Problem in kleinere, gleichartige Teilprobleme zu zerlegen und diese durch wiederholte Selbstaufrufe zu lösen, bis ein einfacher Basisfall erreicht wird.

Grundprinzip der Rekursion

Eine rekursive Funktion besteht aus zwei zwingenden Komponenten: dem Basisfall (auch Abbruchbedingung genannt) und dem rekursiven Fall (Rekursionsschritt). Ohne einen definierten Basisfall kommt es zu einer Endlosrekursion, die in den meisten Programmiersprachen zu einem Laufzeitfehler führt.

Basisfall (Abbruchbedingung)

Der Basisfall definiert eine Bedingung, bei deren Erfüllung die Rekursion endet. Dieser Zustand liefert eine endgültige Lösung, ohne dass die Funktion erneut aufgerufen werden muss. Der Basisfall verhindert, dass die Rekursion unendlich weiterläuft.

Rekursiver Fall (Rekursionsschritt)

Im rekursiven Fall ruft sich die Funktion selbst mit veränderten Parametern auf. Dabei wird das Problem schrittweise verkleinert, bis die Problemgröße so gering ist, dass sie direkt durch den Basisfall gelöst werden kann.

Klassisches Beispiel: Fakultät

Die Fakultät einer Zahl n (geschrieben als n!) ist das Produkt aller positiven ganzen Zahlen von 1 bis n. Die Fakultät lässt sich elegant rekursiv definieren: n! = n * (n-1)!, wobei 0! = 1 als Basisfall dient.

public static int fakultaet(int n) {
    // Basisfall: Fakultät von 0 ist 1
    if (n == 0) {
        return 1;
    }
    // Rekursiver Fall: n! = n * (n-1)!
    return n * fakultaet(n - 1);
}

// Aufruf: fakultaet(5) ergibt 120

Der Aufruf fakultaet(5) führt zu folgender Aufrufkette: 5 * fakultaet(4) = 5 * 4 * fakultaet(3) = 5 * 4 * 3 * fakultaet(2) = 5 * 4 * 3 * 2 * fakultaet(1) = 5 * 4 * 3 * 2 * 1 * fakultaet(0) = 120.

Fibonacci-Folge

Ein weiteres klassisches Beispiel ist die Fibonacci-Folge, bei der jede Zahl die Summe der beiden vorhergehenden Zahlen ist. Hier ruft sich die Funktion sogar zweimal selbst auf (binäre Rekursion).

public static int fibonacci(int n) {
    // Basisfall: Die ersten beiden Fibonacci-Zahlen
    if (n <= 1) {
        return n;
    }
    // Rekursiver Fall: fib(n) = fib(n-1) + fib(n-2)
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// fibonacci(6) ergibt 8 (Folge: 0, 1, 1, 2, 3, 5, 8)

Rekursion vs. Iteration

Rekursion und Iteration sind zwei unterschiedliche Ansätze, um wiederholte Berechnungen durchzuführen. Bei der Iteration verwendest du Schleifen (for, while), bei der Rekursion ruft sich die Funktion selbst auf. Beide Ansätze sind gleich mächtig - jede Rekursion lässt sich auch iterativ lösen und umgekehrt.

Aspekt Rekursion Iteration
Lesbarkeit Oft eleganter bei baumartig strukturierten Problemen Einfacher bei linearen Abläufen
Speicherverbrauch Höher durch Call-Stack Geringer, nur Schleifenvariablen
Performance Kann langsamer sein durch Funktionsaufrufe In der Regel schneller
Stack Overflow Möglich bei tiefer Rekursion Kein Risiko
Eignung Bäume, Graphen, hierarchische Strukturen Listen, einfache Wiederholungen

Die Wahl zwischen Rekursion und Iteration hängt vom konkreten Problem ab. Für hierarchische Datenstrukturen wie Bäume ist Rekursion oft die natürlichere und verständlichere Lösung. Bei einfachen Schleifen über Listen ist Iteration in der Regel effizienter.

Anwendungsgebiete

Rekursion ist besonders geeignet für Probleme, die eine natürliche hierarchische oder baumartige Struktur aufweisen. In der Softwareentwicklung begegnet dir Rekursion in vielen Bereichen.

Datenstrukturen

Viele Datenstrukturen sind von Natur aus rekursiv definiert. Ein Binärbaum besteht beispielsweise aus einem Wurzelknoten und zwei Unterbäumen, die selbst wieder Binärbäume sind. Das Durchlaufen (Traversieren) solcher Strukturen erfolgt elegant mit rekursiven Algorithmen.

  • Baumstrukturen: Binärbäume, AVL-Bäume, B-Bäume
  • Graphen: Tiefensuche (Depth-First Search)
  • Verzeichnisstrukturen: Rekursives Durchsuchen von Dateisystemen
  • DOM-Bäume: HTML/XML-Dokumentenverarbeitung

Algorithmen

Viele bekannte Algorithmen basieren auf dem rekursiven Prinzip "Teile und Herrsche" (Divide and Conquer). Dabei wird ein großes Problem in kleinere Teilprobleme zerlegt, diese rekursiv gelöst und die Teilergebnisse anschließend kombiniert.

  • Quicksort: Effizientes Sortierverfahren mit durchschnittlich O(n log n)
  • Mergesort: Stabiles Sortierverfahren mit garantiert O(n log n)
  • Binäre Suche: Effiziente Suche in sortierten Arrays
  • Turmprobleme: Türme von Hanoi

Vor- und Nachteile

Vorteile

  • Eleganz: Rekursive Lösungen sind oft kürzer und verständlicher
  • Natürliche Abbildung: Hierarchische Probleme lassen sich direkt umsetzen
  • Zustandsspeicherung: Jeder Aufruf speichert seinen eigenen Zustand auf dem Stack
  • Wartbarkeit: Weniger fehleranfällig bei komplexen Strukturen

Nachteile

  • Speicherverbrauch: Jeder Aufruf belegt Speicher auf dem Call-Stack
  • Stack Overflow: Bei zu tiefer Rekursion kann der Stack überlaufen
  • Performance: Funktionsaufrufe haben einen gewissen Overhead
  • Debugging: Der Programmfluss kann schwerer nachzuvollziehen sein

Optimierungstechniken

Es gibt verschiedene Techniken, um die Nachteile rekursiver Algorithmen abzumildern.

Tail-Rekursion

Bei der Tail-Rekursion (Endrekursion) ist der rekursive Aufruf die letzte Operation in der Funktion. Moderne Compiler können solche Rekursionen automatisch in iterativen Code umwandeln, wodurch der Stack-Overhead eliminiert wird.

// Tail-rekursive Fakultät mit Akkumulator
public static int fakultaetTail(int n, int akkumulator) {
    if (n == 0) {
        return akkumulator;
    }
    return fakultaetTail(n - 1, n * akkumulator);
}

// Aufruf: fakultaetTail(5, 1) ergibt 120

Memoisation

Memoisation ist eine Optimierungstechnik, bei der bereits berechnete Ergebnisse zwischengespeichert werden. Wenn dieselbe Berechnung erneut benötigt wird, kann das gespeicherte Ergebnis direkt zurückgegeben werden. Das ist besonders nützlich bei der Fibonacci-Berechnung, wo ohne Memoisation viele Werte mehrfach berechnet werden.

private static Map<Integer, Integer> cache = new HashMap<>();

public static int fibonacciMemo(int n) {
    if (cache.containsKey(n)) {
        return cache.get(n);
    }
    if (n <= 1) {
        return n;
    }
    int result = fibonacciMemo(n - 1) + fibonacciMemo(n - 2);
    cache.put(n, result);
    return result;
}

Rekursion in der Praxis

Rekursion ist ein fundamentales Konzept in der Programmierung, das dir in vielen praktischen Situationen begegnet. Besonders bei der Arbeit mit Dateisystemen, JSON-Datenstrukturen oder XML-Dokumenten wirst du rekursive Algorithmen einsetzen.

In der Ausbildung zum Fachinformatiker für Anwendungsentwicklung lernst du Rekursion als wichtige Programmiertechnik kennen. Das Verständnis rekursiver Denkweisen hilft dir dabei, komplexe Probleme elegant zu lösen und die Funktionsweise vieler Algorithmen und Datenstrukturen nachzuvollziehen.

Quellen und weiterführende Links