Rekursion

Ein Beispiel von Rekursion: Rückkopplung im VLC media player bei anzeigen des eigenen Bildschirms.

Als Rekursion (lateinisch recurrere ‚zurücklaufen‘) bezeichnet man den abstrakten Vorgang, dass Regeln auf ein Produkt, das sie hervorgebracht haben, von neuem angewandt werden. Hierdurch entstehen potenziell unendliche Schleifen. Regeln bzw. Regelsysteme heißen rekursiv, wenn sie die Eigenschaft haben, Rekursion im Prinzip zuzulassen.

Rekursion ist ein zentraler Begriff in Mathematik, Logik und Informatik und hat vielfältige Anwendungen darüber hinaus; diese reichen bis in die Kunst, wo das Phänomen auch als mise en abyme bezeichnet worden ist.

Rekursion ist auch eine Problemlösungsstrategie. Komplexe Sachverhalte können oft mit rekursiv formulierten Regeln sehr elegant erfasst werden. Das Grundprinzip ist dabei dann das Zurückführen einer allgemeinen Aufgabe auf eine einfachere Aufgabe derselben Klasse. Beispielsweise ist die rekursive Programmierung Bestandteil vieler Programmiersprachen. Prozeduren oder Funktionen können sich dabei selbst aufrufen. Rekursion und Iteration sind im Wesentlichen gleichmächtige Sprachmittel.

In Mathematik, Logik und Informatik erscheint Rekursion spezieller in der Form, dass eine Funktion in ihrer Definition selbst nochmals aufgerufen wird (rekursive Definition). Wenn man mehrere Funktionen durch wechselseitige Verwendung voneinander definiert, spricht man von wechselseitiger Rekursion. Nicht jede rekursive Definition ist eine Definition im eigentlichen Sinn, denn die zu definierende Funktion braucht nicht wohldefiniert zu sein. Jeder Aufruf der rekursiven Funktion muss sich durch Entfalten der rekursiven Definition in endlich vielen Schritten auflösen lassen. Ist dies nicht erfüllt, so spricht man von einem infiniten Regress (in der Informatik auch als Endlosschleife bezeichnet).

Anwendungsbereiche und Beispiele für Rekursion

Rekursive Grafiken

„Sprießender“ Pythagoras-Baum

Unter anderem können auch Punktmengen rekursiv definiert werden (dies ergibt die sogenannten Fraktale). Deren graphische Darstellung liefert ästhetisch ansprechende, natürlich aussehende Gebilde. Ein Beispiel ist der Pythagoras-Baum. Der dazugehörige Algorithmus sieht folgendermaßen aus; der dritte Teil enthält die Rekursion:

Der Algorithmus wird dann bis zu einer vorgegebenen Rekursionstiefe entfaltet. Bei Rekursionstiefe eins entsteht ein Dreieck mit je einem Quadrat über den drei Seiten. Das sieht wie die Illustration zum Satz des Pythagoras aus – daher der Name. Je höher die Rekursionstiefe, desto mehr ähnelt das Gebilde einem Baum.

Rekursion in der Grammatik

Die Grammatik natürlicher Sprachen wird in der Linguistik u.a. mit Hilfe von sogenannten Phrasenstrukturregeln beschrieben. Nach Ansicht der meisten Linguisten zeigen dabei alle menschlichen Sprachen die Eigenschaft, rekursiv aufgebaut zu sein (im Gegensatz zu Signalsystemen im Tierreich). Dies ergibt sich, weil in der Zerlegung einer grammatischen Einheit, die mit einer Kategorie etikettiert wird, dieselbe Kategorie erneut auftauchen kann. Ein Beispiel ist das Phänomen der Nebensätze, das hier mit folgender stark vereinfachter Produktionsregel beschrieben ist:

  1. S → NP VP (ein Satz besteht aus einer Nominalphrase (als Subjekt) und einer Verbalphrase)
  2. VP → V NP* (eine Verbalphrase besteht aus einem Verb und null bis vielen Nominalphrasen als Objekten des Verbs)
  3. VP → V S (eine Verbalphrase besteht aus einem Verb und einem Nebensatz als Objekt des Verbs)

Diese Grammatik lässt die Wahl, ob die Ausbuchstabierung von „VP“ mit Regel 2 oder 3 erfolgen soll. Für den Fall, dass die Schritte 1 und dann 3 aufgerufen werden, ergibt sich eine Rekursion: Als Produkt von Regel 3 erscheint das Symbol S, das wiederum den Start für Regel 1 darstellt.

Siehe auch: Produktionsregel

Rekursion in der Mathematik

Fakultät

Die Funktion Fakultät einer Zahl n > 1 ist definiert als das Produkt der Zahlen 1 bis n:

{\displaystyle n!=1\cdot 2\cdot 3\dotsm n=\prod _{k=1}^{n}k}

Beispiele

{\displaystyle {\begin{array}{rll}1!&=1&=1\\2!&=1\cdot 2&=2\\3!&=1\cdot 2\cdot 3&=6\\4!&=1\cdot 2\cdot 3\cdot 4&=24\\\end{array}}}

Soll diese Liste fortgesetzt werden, ergibt sich die Rekursivität nahezu von selbst. Für die Berechnung von 5! wird man nicht von vorn beginnen, sondern kann auf vorherige Ergebnisse zurückgreifen, also

{\displaystyle 5!=4!\cdot 5=120}

Verallgemeinert lässt sich die Funktion somit rekursiv definieren:

{\displaystyle n!=\left\{{\begin{matrix}1&&{\text{falls }}n=1&&{\text{(Rekursionsanfang)}}\\(n-1)!\cdot n&&{\text{sonst}}&&{\text{(Rekursionsschritt)}}\end{matrix}}\right.}

Die Fibonacci-Folge

Ein klassisches Beispiel für eine rekursive Funktion ist die Fibonacci-Folge, bei der jedes weitere Folgenglied die Summe der beiden vorhergehenden ist:

0,1,1,2,3,5,8,13,21,34,\dotsc

Im Gegensatz zur Fakultätsfunktion gibt es hier keine triviale geschlossene Darstellung. Die einfachste Beschreibung ist die rekursive Definition:

\operatorname {fib} (n)=\left\{{\begin{matrix}0&&{\text{falls }}n=0&&{\text{(Rekursionsanfang)}}\\1&&{\text{falls }}n=1&&{\text{(Rekursionsanfang)}}\\\operatorname {fib} (n-1)+\operatorname {fib} (n-2)&&{\text{sonst}}&&{\text{(Rekursionsschritt)}}\end{matrix}}\right.

Diese rekursive Definition ist kaskadenförmig. Die dritte Fibonacci-Zahl wird anhand dieser Definition folgendermaßen berechnet:

{\begin{matrix}\operatorname {fib} (3)&=&\operatorname {fib} (2)+\operatorname {fib} (1)&{\text{(Rekursionsschritt)}}\\&=&\operatorname {fib} (1)+\operatorname {fib} (0)+\operatorname {fib} (1)&{\text{(Rekursionsschritt)}}\\&=&1+\operatorname {fib} (0)+\operatorname {fib} (1)&{\text{(Rekursionsanfang)}}\\&=&1+0+\operatorname {fib} (1)&{\text{(Rekursionsanfang)}}\\&=&1+0+1&{\text{(Rekursionsanfang)}}\\&=&2\end{matrix}}

Die Berechnung für \operatorname {fib} (1) wird hier mehrfach durchgeführt. Das deutet an, dass es Potential für Optimierungen gibt.

Rekursive Definition einer Funktion und Untertypen von Rekursion

Mathematische Definition

(Hinweis vorab: Rekursionsverfahren und rekursive Definitionen sind nicht auf Funktionen natürlicher Zahlen beschränkt. Hier sei auf das verallgemeinerte Rekursionsschema verwiesen.)

Das Grundprinzip der rekursiven Definition einer Funktion f ist: Der Funktionswert f(n+1) einer Funktion f : N0N0 ergibt sich durch Verknüpfung bereits berechneter Werte f(n), f(n-1), … Falls die Funktionswerte von f für hinreichend viele Startargumente bekannt sind, kann jeder Funktionswert von f berechnet werden. Bei einer rekursiven Definition einer Funktion f ruft sich die Funktion so oft selbst auf, bis eine durch den Aufruf der Funktion veränderte Variable einen vorgegebenen Zielwert erreicht oder Grenzwert überschritten hat (Terminierung, Abbruchbedingung).

Die Definition von rekursiv festgelegten Funktionen ist eine grundsätzliche Vorgehensweise in der funktionalen Programmierung. Ausgehend von einigen gegebenen Funktionen (wie z.B. der Summenfunktion) werden neue Funktionen definiert. Mit diesen können weitere Funktionen definiert werden.

Ein Spezialfall der Rekursion ist die primitive Rekursion, die stets durch eine Iteration ersetzt werden kann. Bei einer solchen Rekursion enthält der Aufrufbaum keine Verzweigungen, das heißt, er ist eine Aufrufkette: das ist immer dann der Fall, wenn eine rekursive Funktion sich selbst jeweils nur einmal aufruft. Der Aufruf kann dabei am Anfang (Head Recursion) oder am Ende (Tail Recursion oder Endrekursion) der Funktion erfolgen. Umgekehrt kann jede Iteration durch eine primitive Rekursion ersetzt werden, ohne dass sich dabei die Komplexität des Algorithmus ändert.

Formen der Rekursion

Die häufigste Rekursionsform ist die lineare Rekursion, bei der in jedem Fall der rekursiven Definition höchstens ein rekursiver Aufruf vorkommen darf. Die Berechnung verläuft dann entlang einer Kette von Aufrufen.

Die primitive Rekursion ist ein Spezialfall der linearen Rekursion. Hier definiert man Funktionen auf den natürlichen Zahlen, wobei in jedem rekursiven Aufruf dessen erster Parameter um Eins ab- oder zunimmt. Jede primitiv-rekursive Definition kann unter Zuhilfenahme eines Stapels durch eine Schleife (Programmierung) (z.B. For-Schleife oder While-Schleife) ersetzt werden.

Die endständige oder repetitive Rekursion (Tail Recursion oder Endrekursion) bezeichnet den Spezialfall der linearen Rekursion, bei der jeder rekursive Aufruf die letzte Aktion des rekursiven Aufrufs ist. Endrekursionen lassen sich unmittelbar durch While-Schleifen ersetzen und umgekehrt.

Unter verschachtelter Rekursion versteht man eine Rekursion, bei welcher rekursive Aufrufe in Parameterausdrücken rekursiver Aufrufe vorkommen. Diese Rekursionsform gilt als außerordentlich schwer zu durchschauen.

Kaskadenförmige Rekursion bezeichnet den Fall, in dem mehrere rekursive Aufrufe nebeneinander stehen. Die rekursiven Aufrufe bilden dann einen Baum. Kaskadenförmige Rekursion gilt als elegant, kann aber ohne weitere Maßnahmen einen exponentiellen Berechnungsaufwand nach sich ziehen. Sie wird gerne als Ausgangspunkt für die Ableitung einer anderen effizienteren Formulierung gebraucht.

Die wechselseitige Rekursion bezeichnet die Definition mehrerer Funktionen durch wechselseitige Verwendung voneinander. Sie lässt sich auf die gewöhnliche Rekursion einer tupelwertigen Funktion zurückführen.

Weitere Anwendungen: Rekursion in der Programmierung

Höhere Programmiersprachen die mit Funktionen arbeiten, erlauben üblicherweise auch die Rekursion. Zumeist lassen sich Lösungen rekursiv oder iterativ lösen, siehe Rekursive Programmierung und Iterative Programmierung.

Häufig ist der Quelltext einer rekursiven Programmierung eleganter als die iterative Umsetzung, da keine Hilfsvariablen und Schleifenzähler definiert werden müssen. In der Abarbeitung sind iterative Verfahren meist effizienter und benötigen weniger Speicherplatz. Grund ist das Ablegen der wiederholten Funktionsaufrufe mit allen zwischengespeicherten Werten auf dem Stapelspeicher (Stack). Insbesondere kann die Rekursion auch einen Pufferüberlauf (Stack Overflow) verursachen. Bei der Programmierung von Echtzeitsystemen auf Mikrocontrollern wird daher häufig auf Rekursion verzichtet.

Manche Programmiersprachen (zum Beispiel in der Funktionalen Programmierung) erlauben keine Iteration, sodass immer die rekursive Umsetzung gewählt werden muss. Solche Sprachen setzen zur Optimierung häufig primitive Rekursionen ein, die intern als Iterationen umgesetzt sind (einige Interpreter für LISP und Scheme verfahren so).

Es ist zu beachten, dass eine naive Implementierung bei manchen Funktionen (z.B. den Fibonacci-Zahlen) bedingt, dass Teillösungen mehrfach berechnet werden. Abhilfe schafft in diesem Beispiel die Memoisation, die auf der Wiederverwendung bereits berechneter Zwischenlösungen beruht. Die Rekursion ist ein wesentlicher Bestandteil einiger Entwurfsstrategien für effiziente Algorithmen, insbesondere der Teile-und-herrsche-Strategie (Divide and Conquer). Andere Ansätze (zum Beispiel sogenannte Greedy-Algorithmen) verlangen ein iteratives Vorgehen. Rekursion und primitiv-rekursive Funktionen spielen eine große Rolle in der theoretischen Informatik, insbesondere in der Komplexitätstheorie und Berechenbarkeitstheorie (siehe auch Lambda-Kalkül und Ackermannfunktion).

Programmierbeispiele

Das folgende Beispiel zeigt eine einfache und beliebte Implementierung der Fakultätsfunktion in der Programmiersprache Python. Der rekursiven Variante wird hier zur Verdeutlichung eine iterative Variante gegenübergestellt. Die Rekursion kommt dadurch zum Ausdruck, dass die Funktion sich selbst mit einem um 1 verringerten Argument aufruft. Beide Implementierungen führen den Algorithmus mit linearer Laufzeitkomplexität in Abhängigkeit zum Eingabeparameter aus. Während die Platzkomplexität bei der iterativen Variante konstant bleibt, wächst der Speicherbedarf bei der rekursiven Variante linear an, da bei jedem rekursiven Funktionsaufruf ein neuer Speicherbereich für die lokalen Variablen und die Rücksprungadresse reserviert werden muss. Bei der funktionalen Programmierung wird die dynamische Speicherverwaltung durch einen Aufrufstapel realisiert.

Iterative Programmierung Rekursive Programmierung
def factorial(number):
    result = 1
    
    while number > 1:
        result *= number
        number -= 1
    
    return result
def factorial(number):
    if number <= 1:
        return 1
    
    return number * factorial(number - 1)

Das nächste Beispiel implementiert die Fibonacci-Folge in der Programmiersprache C. Bei der rekursiven Variante handelt es sich um eine Mehrfachrekursion, die zu einer exponentiellen Laufzeit- und Platzkomplexität führt. Die rekursiven Funktionsaufrufe verzweigen sich zu einem Binärbaum, bei dem identische Teilergebnisse mehrfach berechnet werden. Am häufigsten werden die Fibonaccizahlen an den ersten beiden Stellen berechnet, welche die Abbruchbedingung in der Rekursion definieren. Bei der iterativen Variante ist die Laufzeitkomplexität linear und die Platzkomplexität konstant.

Iterative Programmierung Rekursive Programmierung
int fibonacci(int number) {
    int first = 0, second = 1;

    for (int count = 0; count < number; ++count) {
        int swap = first;
        first = second;
        second += swap;
    }

    return first;
}
int fibonacci(int number) {
    if (number <= 0)
        return 0;

    if (number == 1)
        return 1;

    return fibonacci(number - 1) + fibonacci(number - 2);
}

Lösen von Rekursionen

Beim Lösen einer Rekursion sucht man zum einen den Laufzeitaufwand, zum anderen die explizite Form der Rekursion.

Der Aufwand kann als asymptotische Θ- bzw. Ο-Schranke mittels Mastertheorem bzw. Substitutionsmethode bestimmt werden. Auch das geschickte Raten mit anschließender Induktion bietet eine Möglichkeit, eine Oberschranke der Laufzeit zu ermitteln.

Die explizite Form (oder auch geschlossene Form genannt) der Rekursionsgleichung lässt sich beispielsweise durch die Erzeugende-Funktion finden. Eine zweite Möglichkeit bietet das Ableiten durch Differenzenbildung aufeinanderfolgender Funktionswerte der Rekurrenz.

Verwendung des Konzepts Rekursion in weiteren Wissenschaften

Das Konzept der Rekursion wird in verschiedenen Disziplinen auf unterschiedliche Weise verwendet. Es lassen sich fünf Arten des Gebrauchs unterscheiden: Von der „linear-iterativen“ Rekursion in Mathematik und Informatik und der „generativ-hierarchischen“ Rekursion in Grammatik und Linguistik unterscheiden sich die „organisatorisch-syntaktische“ Rekursion in der Kognitionspsychologie, die „operativ-funktionale“ Rekursion in der Techniktheorie und die „prozessemulative“ Rekursion in der Kulturevolutions- und Zivilisationstheorie.

Kognitionspsychologie

Einen „organisatorisch-syntaktischen“ Begriff der Rekursion arbeitete der evolutionäre Kognitionspsychologe Michael Corballis in seinem Buch The Recursive Mind aus. Er zeigt, dass die menschliche Fähigkeit zur prinzipiell beliebig tiefen Verschachtelung von Sinn- und Handlungsebenen und zur offenen syntaktischen Aneinanderreihung von Operationseinheiten, wie sie grundsätzlich im Werkzeugverhalten und der Kooperation auftreten, der Sprachfähigkeit vorausgeht und ein allgemeines Merkmal der menschlichen Kognition und Handlungsorganisation ist. So beruhen die beim Menschen stark ausgeprägten Vermögen zu mentalen Zeitreisen und zur Theory of Mind grundsätzlich auf dem Vermögen zur Rekursion.

Techniktheorie

Einen „operativ-funktionalen“ Begriff der Rekursion entwickelte der Systhemtheoretiker W. Brian Arthur in seinem Buch The Nature of Technology. Arthur zeigt, dass alle Technologien eine hierarchische Verschachtelung von Elementen und Funktionsebenen aufweisen, wobei die unteren Elemente ihre operative Funktionalität durch Rekursion zu den oberen Ebenen erhalten, wie er am Beispiel eines Flugzeugträgerverbandes illustriert: Die Turbine eines Kampfjets besteht aus Einzelteilen oder „executables“ wie Schrauben und Luftschaufeln, die rekursiv in die Gesamtfunktion der Turbine eingebettet sind, wie zugleich die Turbine ein rekursiv verschachteltes „executable“ des Kampfjets, der Kampfjet ein „executable“ des Flugzeuträgerverbands und dieser ein „executable“ eines Geschwaders ist.

Kulturevolutionforschung und Zivilisationstheorie

Die gesamte technologische und kulturelle Entwicklung in der Kulturevolution und Zivilisationsgeschichte weist das Muster der „prozessemulativen“ Rekursion auf, wie der Soziologe Davor Löffler nachgewiesen hat. „Prozessemulative“ Rekursion bezeichnet einen Entwicklungsmechanismus, bei dem ein instrumenteller oder geistiger Vorgang abstrahiert und als materielle oder mediale Emulation wieder eingeführt wird. Dies lässt sich an der frühen Technikevolution nachweisen, in der Entwicklungsstufen jeweils als Grade der Rekursion beschrieben werden können. Dem gegenwärtigen Kenntnisstand nach, zusammengefasst im „Modell der Erweiterung kultureller Kapazitäten“, folgen entwicklungsgeschichtlich auf einfache Steinwerkzeuge („Modularkultur“, > 2.6 Ma) Kompositwerkzeuge wie Hammersteine mit Griff oder Speere mit Knochenspitzen („Kompositkultur“, > 500 ka), hierauf aus komplementären, voneinander unabhängigen Modulen zusammengesetzte Apparate wie Pfeil-und-Bogen oder Nadel und Faden („Komplementärkultur“, > 70 ka), hierauf ideelle Werkzeuge wie Höhlenmalereien, Musikinstrumente oder Fallen („ideelle Kultur“, > 40 ka). Die Technologiestrukturen der kumulativ aufeinander aufbauenden Entwicklungsstufen gründen jeweils auf der „prozessemulativen“ Rekursion der Vorgänge der vorherigen Stufen. Beispielsweise emuliert der Apparat des Pfeil-und-Bogens („Komplementärkultur“) rekursiv den Vorgang des Speerwurfs („Kompositkultur“) und die Falle („ideelle Kultur“) emuliert rekursiv die Anwesenheit einer Jägergruppe bzw. der Fallenmechanismus den Auslösemechanismus des Bogens („Komplementärkultur“). Die „prozessemulative“ Rekursion durchzieht als allgemeines Prinzip die gesamte Technikgeschichte: So beruht beispielsweise der Mikrowellenherd auf der „prozessemulativen“ Rekursion, da darin der Vorgang der Erhitzung von Nahrung etwa durch einen Ofen emuliert wird; die digitale Mustererkennung beruht auf der prozessemulativen Rekursion menschlicher Mustererkennung usw. Es wurde gezeigt, dass das Entwicklungsprinzip der „prozessemulativen“ Rekursion auch den Entwicklungen der gesamten Zivilisationsgeschichte zugrunde liegt und neben der Technologie auch in anderen Bereichen auftritt, etwa der Ökonomie, den Medien, der Politik, der Entwicklung von Kognitionsstrukturen, der Kunst und der Mathematik, wobei wiederum jede Entwicklungsstufe dieser Bereiche auf der rekursiven Emulation der Vorgänge der vorherigen Entwicklungsstufe beruht. So lassen sich kumulativ aufeinander folgende Entwicklungsphasen der Zivilisationsgeschichte (frühe Hochkulturen, Achsenzeit und Neuzeit) als Ausdruck von „prozessemulativen“ Rekursionen erklären.

Siehe auch

Trenner
Basierend auf einem Artikel in: externer Link Wikipedia.de
Seitenende
Seite zurück
©  biancahoegel.de
Datum der letzten Änderung: Jena, den: 06.01. 2024