scripting:tutorials:level2:recursion
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Nächste Überarbeitung | Vorherige Überarbeitung | ||
scripting:tutorials:level2:recursion [2023/11/23 16:27] – angelegt fritz_98 | scripting:tutorials:level2:recursion [2023/11/24 10:06] (aktuell) – [Endrekursion] fritz_98 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
======Rekursionen====== | ======Rekursionen====== | ||
- | Rekursive Funktionen sind Funktionen, die sich während ihrer Ausführung selbst aufrufen. Dabei kann sich die Funktion sogar mehrmals selbst oder zwei Funktionen sich gegenseitig aufrufen. | + | Rekursive Funktionen sind Funktionen, die sich während ihrer Ausführung selbst aufrufen. Dabei kann sich die Funktion sogar mehrmals selbst oder zwei Funktionen sich gegenseitig aufrufen. Rekursive Funktionen stehen im Gegensatz zu iterativen Funktionen, die [[ scripting: |
Damit sie das nicht endlos tun, muss jede rekursive Funktion eine Bedingung formulieren, | Damit sie das nicht endlos tun, muss jede rekursive Funktion eine Bedingung formulieren, | ||
Zeile 7: | Zeile 7: | ||
Jede rekursive Funktion besitzt demnach einen Basisfall bzw. eine Abbruchbedingung, | Jede rekursive Funktion besitzt demnach einen Basisfall bzw. eine Abbruchbedingung, | ||
- | Verdeutlicht an einem Beispiel: | + | ---- |
+ | |||
+ | **Hinweis**: Unsere Beispiele in diesem und den folgenden Kapiteln können besser nachvollzogen werden, wenn man die Programmzeilen nebenbei ausprobieren kann. Dazu kann man diese Webseite hier verwenden: | ||
+ | |||
+ | [[ https:// | ||
+ | |||
+ | ---- | ||
====Beispiel: | ====Beispiel: | ||
Zeile 31: | Zeile 37: | ||
- Es gibt eine Abbruchbedingung, | - Es gibt eine Abbruchbedingung, | ||
- | - Der rekursive Aufruf gibt als Argument eine kleinere Zahl ('' | + | - Der rekursive Aufruf gibt als Argument eine kleinere Zahl ('' |
Zur Veranschaulichung können wir den Funktionsaufruf '' | Zur Veranschaulichung können wir den Funktionsaufruf '' | ||
Zeile 45: | Zeile 51: | ||
24 <- an der Stelle ist bekannt: Factorial(4) = 24, das Ergebnis ist fertig | 24 <- an der Stelle ist bekannt: Factorial(4) = 24, das Ergebnis ist fertig | ||
</ | </ | ||
+ | |||
+ | **Hinweis**: | ||
+ | |||
\\ | \\ | ||
====Zusammenhang mit Schleifen==== | ====Zusammenhang mit Schleifen==== | ||
- | (+ Beispiel | + | Die Voraussetzung, |
+ | |||
+ | Um diese Behauptung zu untermauern und ein weiteres rekursives | ||
+ | |||
+ | <code lua> | ||
+ | -- Rekursive Variante des Euklidischen Algorithmus | ||
+ | function GreatestCommonDivisor(_A, | ||
+ | -- Diese Abbruchbedingung war bereits Teil der ursprünglichen Formulierung | ||
+ | if _A == 0 then | ||
+ | return _B | ||
+ | end | ||
+ | -- Diese Abbruchbedingung ist die gleiche wie die der while-Schleife in der ursprünglichen | ||
+ | -- Formulierung. Auch in der Schleifen-Version des Algorithmus wird _A zurückgegeben, | ||
+ | -- _B == 0 ist. Damit in diesem Fall keine weiteren rekursiven Aufrufe mehr passieren, | ||
+ | -- steht diese Bedingung hier oben | ||
+ | if _B == 0 then | ||
+ | return _A | ||
+ | end | ||
+ | |||
+ | -- Diese Bedingung ist ebenfalls die gleiche wie in der ursprünglichen Formulierung | ||
+ | -- Die Fallunterscheidung entscheidet, | ||
+ | -- verringert wird. Dadurch wird sichergestellt, | ||
+ | -- Da sowohl _A als auch _B an der Stelle größer 0 sein müssen (sonst wäre die Funktion oben | ||
+ | -- bereits mit return ausgestiegen), | ||
+ | -- zwangsweise der 0, was die Abbruchbedingung ist | ||
+ | -- Der Rekursive Aufruf geschieht pro Funktionsaufruf höchstens 1 mal, da nur einer der beiden | ||
+ | -- Fälle eintreten kann | ||
+ | if _A > _B then | ||
+ | return GreatestCommonDivisor(_A - _B, _B) | ||
+ | else | ||
+ | return GreatestCommonDivisor(_A, | ||
+ | end | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Umgekehrt muss es auch möglich sein, rekursive Funktionen durch Schleifen auszudrücken. Die Berechnung der Fakultät | ||
+ | <code lua> | ||
+ | -- Iterative Version der Berechung der Fakultät | ||
+ | function Factorial(_X) | ||
+ | local Result = 1 | ||
+ | while _X > 1 do | ||
+ | | ||
+ | _X = _X - 1 | ||
+ | end | ||
+ | |||
+ | return Result | ||
+ | end | ||
+ | </ | ||
+ | Es gibt einige Algorithmen, | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ====Endrekursion==== | ||
+ | |||
+ | Die Art und Weise, wie wir oben die Fakultät rekursiv definiert haben, kann für größere Funktionen zu Performanceproblemen führen. Das hat folgenden Grund: Bei jedem rekursiven Aufruf muss sich Lua merken, wie " | ||
+ | <code lua> | ||
+ | return _X * Factorial(_X - 1) | ||
+ | </ | ||
+ | Das Programm muss also zuerst '' | ||
+ | |||
+ | Lua profitiert allerdings von endrekursiven Formulierungen: | ||
+ | |||
+ | Zu dem Zweck soll die Funktion '' | ||
+ | <code lua> | ||
+ | -- Der zweite Parameter _Acc steht für " | ||
+ | function Factorial(_X, | ||
+ | -- Schreibe 1 ins Zwischenergebnis, | ||
+ | -- Dieser Fall ist nur für den ersten Aufruf der Funktion relevant | ||
+ | if not _Acc then | ||
+ | _Acc = 1 | ||
+ | end | ||
+ | |||
+ | -- Das Zwischenergebnis wird bei jeder Rekursion " | ||
+ | -- dieses Zwischenergebnis im Basisfall auszugeben | ||
+ | if _X == 1 then | ||
+ | return _Acc | ||
+ | end | ||
+ | |||
+ | -- Das neue Zwischenergebnis ist das Produkt aus _X und dem bisherigen Zwischenergebnis | ||
+ | return Factorial(_X - 1, _X * _Acc) | ||
+ | end | ||
+ | </ | ||
+ | So aufgeschrieben muss die Funktion nach dem rekursiven Aufruf nichts mehr mit dem Ergebnis machen. Das Zwischenergebnis wird dem rekursiven Aufruf weitergereicht, | ||
+ | < | ||
+ | Factorial(4) | ||
+ | Factorial(3, | ||
+ | Factorial(2, | ||
+ | Factorial(1, | ||
+ | 24 | ||
+ | </ | ||
+ | ---- | ||
- | ====Endrekrusion==== | + | Dieses Kapitel zu Rekursionen dient hauptsächlich zum Verständnis des Konzepts. Vielen fällt die Formulierung in Schleifen leichter als Rekursionen. Wahrscheinlich findest du in Skripten anderer Mapper aber immer wieder rekursive Funktionen, auch solche, die sich nicht iterativ ausdrücken lassen (wegen beispielsweise mehrerer rekursiver Aufrufe). Ein anderes Beispiel ist der [[ https:// |
- | ====Relevanz | + | Im nächsten Kapitel diskutieren wir einige Arten von Komfortfunktionen, |
+ | [[ scripting: | ||
+ | [[ scripting: | ||
+ | [[ scripting: |
scripting/tutorials/level2/recursion.1700756831.txt.gz · Zuletzt geändert: 2023/11/23 16:27 von fritz_98