R E K U R S I O N Eine Prozedur ( insbesondere Funktion ) heißt Teil enthält. R E K U R S I V, wenn sie sich selbst als REKURSION ist also WIEDERHOLUNG durch SCHACHTELUNG, die Vorgangsweise ist "TOP - DOWN" , d.h. vom ALLGEMEINEN ---> zum ---> BESONDEREN. ITERATION ist WIEDERHOLUNG durch ANEINANDERREIHUNG, die Vorgangsweise ist "BOTTOM - UP" , d.h. vom BESONDEREN --> zum --> ALLGEMEINEN. Jede REKURSIVE Prozedur kann in eine gleichwertige ITERATIVE umgewandelt werden - und umgekehrt. Damit Rekursion nicht zu einem unendlichen Regreß führt, bedarf sie eines REKURSIONSANFANGS; er entspricht der ABBRUCHBEDINGUNG bei Iterationen. Ein einfaches Beispiel: Es ist die Summe s(n) aller natürlichen Zahlen von 1 bis n zu berechnen ! s(n) = 1+2+3+4+5+6+ ...... +n a) ITERATIVE LÖSUNG ( Struktur : SCHLEIFE! ) function summe(n:integer):integer; var i,s : integer; begin s:=0; for i:=1 to n do Aufruf vom Hauptprogramm aus mit s := s + i; z.B. summe(5); summe:=s; end; b) REKURSIVE LÖSUNG ( Schachtelung ) Die Summe der ersten n Zahlen kann folgendermaßen definiert werden : s(n) = n + s(n-1) für n>0 und nun die Prozedur ( Funktion ) : Rekursionsanfang : s(0) = 0 function summe(n:integer):integer; begin if n=0 then summe:=0 else summe:=n + summe(n-1); end; . . ( hier ruft sich die Funktion selbst auf!) Rekursive Programme sind für den Benutzer einfach ( wenn man Rekursion,versteht ! ) , iterative für den Computer. Ein rekursiver Prozeduraufruf erfordert, daß der vorhergehende Aufruf unterbrochen wird, die lokalen Größen müssen bis zur Fortsetzung der unterbrochenen Prozedur festgehalten werden, ---> dies erfordert Speicherplatz und Zeit. Ein Problem läßt sich rekursiv lösen, wenn es so in kleinere Teile zerlegbar ist, daß auf diese ( Teile ) das gleiche Lösungsverfahren anwendbar ist ---> Strategie des DIVIDE and CONQUER : Ein Problem P wird in Teilprobleme zerlegt, wobei diese dieselbe Struktur aufweisen. Weitere einfache Beispiele : - FAKULTÄTSBERECHNUNG : N ! = 1*2*3*4*5* ... *N = N*(N-1)*(N-2)* ...*2*1 rekursive Definition : n! = n*(n-1)! Rekursionsanfang : 0! = 1 - FIBONACCI - Zahlenfolge : f(n) = f(n-1)+f(n-2) mit f(1)=f(2)=1 - FOLGE der MITTELWERTE : f(n) = (f(n-1)+f(n-2))/2 mit z.B f(1)=0 u. f(2)=6 - GRÖßTER GEMEINSAMER TEILER : es gilt : ggT(a,b) = ggt(a-b,a) wenn a > b (fortgesetzte Subtraktion) z.B.: ggT(64,36)=ggt(28,36)=ggT(36,28)=ggT(8,28)=ggT(28,8)=ggT(20,8) =ggT(12,8)=ggT(4,8)=ggT(8,4)=ggT(4,4) ---> ggT(64,36) = 4 1 -------------Programm: function ggT(a,b begin if a = b then else if a < b else ggT end; : integer):integer; ggT := a then ggT := ggT(b,a) := ggT(a-b,b) Veranschaulichung der REKURSION anhand der Zahlenfolge : A(N)=A(N-1)+1 n=1 mit A(0) = 0 (Folge der natürlichen Zahlen ) Rekursion = beginnend mit Schachtelung ! ................................................... .A(N) . . ......................................... . . .A(N-1) . . . . ............................... . . . . .A(N-2) . . . . . . ....................... . . . . . . .A(N-3) . . . . . . . . ............... . . . . . . . . .A(N-4) bis . . . . . . . . . . Rek.anfang . . . . . . . . . ............... . . . . . . . ....................... . . . . . ............................... . . . . . . . ......................................... . . . ................................................... ......................... . . Realisierung in Pascal : konkretes Beispiel : function .A(N:integer):integer; . begin . . if n=0.then A := 0 . . ......... . .else A :=.A(N-1) .+ 1 . end; . . . . . ......... . ......................... A(4) = ? A(4)=4 A(4) = ^ . ^ . w ^ A(3)=3 i ^ R . r v ^ Ü . d o ^ c A2)=2 m ^ k . ^ r . ^ r A(1)=1 ^ e . ^ c . ^ h . ^ n . ^ u . ^ n . ^ g . ^ . ^ A(0)=0 A(3) : : A(3) + R e k u r s 1 = A(2) + 1 : : C A(2) = A(1) + 1 o : m : p g A(1) = A(0) + 1 u e : t s : e p Rekursionsanfang r e : i 0 (ist bekannt) chert ! ( auf dem STACK ) : ( Teil des RAM ) : ............................ : i o n s t i e f e Was machen folgende 2 fast idente Programme ? 2 procedure rekdemo1; uses crt; procedure rekdemo1; uses crt; procedure wasmachich(n : integer); begin writeln(n); wasmachich(n-1); end; procedure wasmachichjetzt(n : integer); begin wasmachichjetzt(n-1); writeln(n); end; begin wasmachich(10); readln; end. begin wasmachichjetzt(10); readln; end. Noch ein Beispiel: Eine Zeichenfolge, die durch einen Punkt abgeschlossen wird, soll in umgekehrter Reihenfolge dargestellt werden procedure drehe; var ch : char; begin ch:=readkey; write(ch); (Zeichen wird ohne Bestätigung mit RETURN eingelesen) if ch = '.' then writeln else begin drehe; write(ch) end; end; Ein sehr aktuelles Beispiel (Die Lehrplanreform - ein Schachtelsatz!). program der_lehrplan_lebt; uses crt; function reform(jahr : integer) : string; begin if jahr < 1990 then reform:=´Wie gut war der alte Lehrplan!!!´ else if jahr=1990 then reform:=´reformierten Lehrplans´ else reform:=´Reform des ´,reform(jahr-1)); end; begin writeln(reform(1999)); readln; end. 3