Claus SchönleberHitchhacker´s Guide To PASCAL [Vol. 2] |
|||||
|
[ Start | Beispielprogramme Download | Home ] | ||||
InhaltTypisierteKonstanten Sets (Mengen) Rekursion Records Dateien (Random Access) Pointer Algorithmen - Hashing - Sortieren |
RekursionFür die einen die reinste Form der Programmierung, für die anderen Schwarze Magie: Rekursion. Der Grund für solch unterschiedliche Bewertung liegt wohl daran, daß der Mensch nicht oder nicht bewußt rekursiv denkt, sondern iterativ. Iterationen haben wir in Kurs 1 einige kennengelernt: Schleifen in jeder Form. Iterationen sind uns geläufig, immer hübsch eins nach dem andern. Es sind aber andere Lösungsansätze denkbar, und die sehen, wenn man ihr Prinzip durchschaut hat, meist sehr viel kürzer und oft eleganter aus. Rekursionen bedeuten allerdings einen erhöhten Rechneaufwand. In zeitkritischen Systemen sollte man deren Einsatz also sorgfältig planen.Allerdings hat es wenig Sinn, mit Rekursionen zu argumentieren, die sich im Aufwand von Iterationen nicht unterscheiden lassen. Dann ist es wirklich nicht einzusehen, daß Rekursionen überhaupt benötigt werden. In diesem Kapitel werden deshalb zwei Ansätze zur Rekursion aufgeführt:
Was ist Rekursion?Rekursionen (Hier: Rekursive Funktionen/Prozeduren) bestehen grundsätzlich aus zwei Teilen.
Diese rekursive Definition kann sofort in ein Programm umgesetzt werden.[ 1, falls x = 0 x! := < x * (x - 1)!, falls x > 0 [ nichts sonst Konzentrieren wir uns auf die Funktion "fak":PROGRAM recursive1; VAR i : integer; FUNCTION fak (x : integer) : integer; BEGIN IF (x = 0) THEN fak := 1 ELSE fak := x * fak (x - 1); END; BEGIN write ('Zahl: '); readln (i); writeln (i,'! = ',fak (i)); END.
x! := 1 * 2 * 3 * ... * x Ein weiteres Funktionsbeispiel. Die Potenz einer Zahl kann ebenfalls rekursiv definiert werden:PROGRAM fak_it; VAR x,i,f : integer; BEGIN write ('Zahl: '); readln (x); f := 1; FOR i := 1 TO x DO f := f * i; writeln (x,'! = ',f); END. Auch hier ist die Umsetzung in ein Programm höchst trivial:[ 1, falls y = 0 xy := < x * x(y - 1),falls y > 0 [ nichts sonst Vergleichen Sie diese Version mit der iterativen Version aus Kurs 1. Wie oben schon erwähnt, sind diese beiden Beispiele völlig ungeeignet, um Rekursionen zu rechtfertigen. Sie zeigen aber doch in übersichtlicher Weise, wie eine Rekursion abläuft.PROGRAM recursive2; VAR x,y : integer; FUNCTION power2 (base,exponent : integer) : integer; BEGIN IF exponent = 0 THEN power2 := 1 ELSE power2 := base * power2 (base,exponent - 1); END; BEGIN write ('Basis und Exponent eingeben: '); readln (x,y); writeln ('Ergebnis: ',power2 (x,y)); END. Um Ihnen trotzdem einen Vorgeschmack zu geben, wie schwierig manche Probleme werden, wenn man keine Rekursion einsetzen darf, soll zunächst das Problem und dann ein Programmvorschlag besprochen werden. Stellen Sie sich eine Liste vor, zum Beispiel
Die soll jetzt durch Vertauschen beliebiger Elemente in allen möglichen Kombinationen angeordnet werden. Das sieht dann so aus: 1 2 3 1 3 2 2 3 1 2 1 3 3 1 2 3 2 1 Zum Verfahren: die Grundoperation ist das Rotieren einer Liste, wie man an obigem Beispiel leicht nachvollziehen kann. Das wird in der Prozedur "rotate" erledigt. In "permute" wird die Ausgabe auf dem Bildschirm und das Rotieren der aktuellen Unterliste vorgenommen. Die zu permutierende Liste ist in "liste" als String untergebracht. Sie können ja versuchen, dieses Problem anders zu lösen. Aber welche Lösung Sie auch immer finden werden, es wird höchstwahrscheinlich eine, wenn auch versteckt, rekursive Lösung sein.PROGRAM permutations; USES crt; TYPE str = STRING [80]; VAR list : str; max : integer; PROCEDURE rotate (VAR _rlist : str; _len : integer); VAR i : integer; c : char; BEGIN c := _rlist [1]; FOR i := 1 TO _len DO _rlist [i] := _rlist [i + 1]; _rlist [_len] := c; END; PROCEDURE permute (VAR result : str; len : integer); VAR i : integer; BEGIN IF (len = 1) THEN BEGIN FOR i := 1 TO max DO write (result [i]:5); writeln; END ELSE FOR i := 1 TO len DO BEGIN rotate (result,len); permute (result,len - 1); END; END; BEGIN clrscr; list := '123456'; max := length (list); permute (list,max); END. Als Bonbon noch zwei Programme, die Sie als Denksportaufgaben betrachten können. AckermannAls erstes ein Programm, das die 1928 von ACKERMANN gefundene Funktion darstellt. ACKERMANN hat damit bewiesen, daß eine berechenbare Funktion nicht unbedingt primitiv-rekursiv sein muß. Primitiv-rekursiv sind z.B. Fakultät und Potenzfunktion.Die Funktion ruft sich nicht nur einfach selbst auf, sondern auch als Parameter von sich selbst. Das nachzuvollziehen stellt schon eine Herausforderung an die eigene geistige Beweglichkeit dar! Seien Sie nicht traurig, wenn Ihr Computer schon bei dem Parameterpaar ack (4,1) den Geist aufgibt. In der nachfolgenden Tabelle sind einige Werte der Funktion aufgeführt, die Sie, bis auf die letzten beiden, leicht nachprüfen können. Zu jedem Wert steht auch die Zahl der Aufrufe von 'ack', die zur Berechnung des Wertes benötigt werden.PROGRAM ackermann; VAR m,n,o,x : integer; FUNCTION ack (n,m : integer) : integer; BEGIN x := x + 1; IF (n = 0) THEN ack := succ (m) ELSE IF (m = 0) THEN ack := ack (pred (n),1) ELSE ack := ack (pred (n),ack (n,pred (m))); END; BEGIN x := 0; writeln ('Ackermann-Funktion'); write (' Geben Sie zwei Zahlen ein : '); readln (m,n); writeln; o := ack (m,n); writeln; writeln ('ACK (',m,',',n,') = ',o); writeln ('Aufrufe : ',x) END. ack (1,1) = 3 (4 Aufrufe) ack (2,2) = 7 (27 Aufrufe) ack (2,3) = 9 (44 Aufrufe) ack (3,3) = 61 (2432 Aufrufe) ack (3,4) = 125 (10307 Aufrufe) ack (4,2) besitzt 19729 Stellen ack (4,4) ist größer als 10 hoch 10 hoch 10 hoch 19000 McCarthyDas zweite Programm ist ein Beispiel für den sogenannten "Kopierprozeß", der beim Übersetzen von Quelltexten in Maschinensprache aktiv werden muß, damit lokale Variablen, etc. nicht mit gleichen Benennungen aus dem Hauptprogramm kollidieren. Das Programm stammt von John McCarthy, dem Erfinder von LISP. Es ist mit einigem Augenzwinkern geschrieben, da es zeigt, wie man mit viel Aufwand, genial formuliert, fast nichts produziert. Es ist die "91er Funktion", die auch anders formuliert werden kann:Aber hier das Programm:IF x > 100 THEN x := x - 10 ELSE x := 91; PROGRAM mccarthy (input,output); VAR x : integer; PROCEDURE p (VAR s : integer); BEGIN IF s > 100 THEN s := s - 10 ELSE BEGIN s := s + 11; p (s); p (s) END END; BEGIN write ('ZAHL : '); readln (x); p (x); writeln (x) END. Türme von HanoiEiner alten Legende zufolge haben die Mönche in einem alten Kloster in Hanoi die Aufgabe, 64 verschieden große Scheiben, die pyramidenartig auf einer senkrecht zum Boden stehenden Stange aufgereiht sind, auf eine weitere Stange zu transportieren.Dabei gelten folgende zwei Regeln:
PROGRAM towers_of_hanoi; PROCEDURE hanoi (n,ap,zp : integer); BEGIN IF (n > 1) THEN hanoi (n - 1,ap,6 - ap - zp); write ('Scheibe ',n,' von Turm ',ap,' nach Turm ',zp); IF (n > 1) THEN hanoi (n - 1,6 - ap - zp,zp); END; BEGIN (* Beispielaufruf fuer 5 Scheiben, von Turm 1 nach Turm 3 *) hanoi (5,1,3); END. |
||||
|
(c) 2001 Schoenleber.com |