ÜBUNGEN ZUR REKURSION Aufgabe 1: Auf einem früheren Arbeitsblatt wurde eine rekursive DELPHI-Funktion zur Berechnung der Quadratzahl zu einer natürlichen Zahl n vorgestellt, welche mathematisch wie folgt definiert war: quad (n − 1) + n + n − 1 n > 1 quad (n) = 1 n =1 a) Stellen Sie den rekursiven Abstieg grafisch dar. b) Ermitteln Sie für den Funktionsaufruf quad(5) die Gesamtanzahl an Vergleichs- und Strichoperationen. c) Schreiben Sie eine DELPHI-Function quad2(n: integer): integer, welche die Quadratzahl nun iterativ berechnet. Nutzen Sie dazu folgende Beziehung: 1² = 1, 2² = 3 + 1, 3² = 5 + 3 + 1, 4² = 7 + 5 + 3 + 1, 5² = 9 + 7 + 5 + 3 + 1, ... d) Ermitteln Sie auch zu Ihrer Funktion die Gesamtanzahl an Vergleichs und Strichoperationen. Vergleichen Sie mit Teilaufgabe b. Hinweis: Die FOR-Schleife for i:= 1 to n beinhaltet implizit die Addition i:= i + 1 sowie den Vergleich i <= n. Aufgabe 2: Schreiben Sie jeweils eine rekursive Prozedur, welche die folgenden Grafiken erzeugt: a) b) c) Aufgabe 3: Hinter den Ziffernfolgen 1, 121, 1213121, 121312141213121, 1213121412131215121312141213121, ... verbirgt sich ein interessantes rekursives Bildungsgesetz. a) Beschreiben sie dieses Bildungsgesetz in eigenen Worten. b) Schreiben Sie eine Function Ziffernfolge (n: Integer): String, welche die n-te Ziffernfolge als String zurückgibt. c) Warum sollte die Funktion einen String und keine Zahl zurückgeben? Begründen Sie! Aufgabe 4: Betrachten Sie die folgende DELPHI-Prozedur: procedure TF_Wort.Wort(n: Integer; w: string); var i: char; begin if n=0 then M_Ausgabe.Lines.Add(w) else begin for i:= 'A' to 'F' do Wort(n-1,w+i) end; end; a) Beschreiben Sie in eigenen Worten die Wirkung der Prozedur. Welche Ausgabe wird getätigt, wenn die Prozedur mit Wort(3,’’) gestartet wird? b) Wie muss man das Programm abändern, damit die produzierten Worte nur aus unterschiedliche Buchstaben bestehen. Hinweis: Implementierung auch ohne Hilfe des Mengentyps (Set of ...) möglich. Dazu müssen nur in dem vordefinierten Wort ´ABCDEF´ lediglich Buchstaben getauscht anstatt angehängt werden. Aufgabe 5: Wie viele Möglichkeiten gibt es, ein DM-Stück in Ein-, Zwei-, Fünf-, Zehn- und Fünfzigpfennigstücke zu wechseln? Allgemein: Ein Land hat k Münzwerte m[1] = 1, m[2] = ?, ..., m[k] = ?. Auf wie viele Arten kann man b Geldeinheiten mit Hilfe dieser Münzen bezahlen? a) Machen Sie sich klar, dass es für 10 Pfennig insgesamt 11 verschiedene Möglichkeiten der Bezahlung gibt. b) Entwickeln Sie eine rekursive Function a(b, k: Integer): Integer, welche die Anzahl der Möglichkeiten, b Geldeinheiten mit k verschiedenen Münzen m[1..k] zu zahlen, berechnet. Hinweis: Sei a(b,k) die Anzahl der Möglichkeiten, b Geldeinheiten mit Münzen zu bezahlen, deren Werte in der Reihung m[1..k] gespeichert sind; m[1] = 1. Dann lässt sich das Problem auf das kleinere Problem, den Betrag b – m[k] zu wechseln, reduzieren. Es gibt aber a(b−m[k],k) Möglichkeiten, unter Verwendung von m[k] zu zahlen, und a(b,k−1) Möglichkeiten, ohne die Münze vom Wert m[k] zu zahlen. c) Sei m[1..5] = (1,2,5,10,50). Stellen Sie den rekursiven Abstieg für den Aufruf a(10,5) grafisch dar (Baumdiagramm). Begründen Sie damit die 11 Bezahlungsmöglichkeiten aus Teilaufgabe a. d) Entwickeln Sie eine Prozedur, welche alle Möglichkeiten der Bezahlung explizit in einem Memofenster auflistet (siehe rechts abgedrucktes Beispiel-Formular). LÖSUNGEN ZU DEN ÜBUNGEN Aufgabe 1: a) + b) Quad(5) | Quad(5−1) +5+5−1 | Quad(4−1) +4+4−1 | Quad(3−1) +3+3−1 | Quad(2−1) + 2 + 2 − 1 | 1 c) Strichop.: Verleiche: 1 4 1 4 1 4 1 4 1 16 5 Function quad2(n: integer): integer; Var i, Ergebnis: Integer; Begin Ergebnis:= 0 for i:= 1 to n do begin Ergebnis:= Ergebnis + i + i – 1; end; End; d) Anzahl Strichop.: 20 (da i:= i + 1); Anzahl Vergleiche: 6 (da bei i = 6 auch geprüft wird). Aufgabe 2: a) Procedure Baum(n: Integer; Laenge: Real); Begin VW(Laenge); if n>1 then begin DL(45); Baum(n-1, Laenge*0.7) DR(90); Baum(n-1, Laenge*0.7) DL(45); end; RW(Laenge); End; b) Procedure Quadrat(n: Integer; Laenge: Real); Begin VW(Laenge/2); for i := 1 to 3 do begin DR(135); if n>1 then Quadrat(n-1, Laenge/2); DR(135); VW(Laenge); end; DR(135); if n>1 then Quadrat(n-1, Laenge/2); DR(135); VW(Laenge/2); End; c) Procedure Trauerweide(n: Integer; Laenge: Real); Begin VW(Laenge); DL(15); if n>1 then VW(Laenge); if n>1 then VW(Laenge); if n>1 then VW(Laenge); RW(Laenge); if n>1 then VW(Laenge); if n>1 then VW(Laenge); if n>1 then VW(Laenge); RW(Laenge); End; Trauerweide DR(15); Trauerweide DR(15); Trauerweide RW(Laenge); DR(45); (n-1, Laenge); (n-1, Laenge); (n-1, Laenge); DL(15); RW(Laenge); DL(15); Trauerweide (n-1, Laenge); DL(15); Trauerweide (n-1, Laenge); DL(15); Trauerweide (n-1, Laenge); RW(Laenge); DR(15); RW(Laenge); DR(15); DL(30); RW(Laenge); Aufgabe 3: a) Eine neue Zahl entsteht durch Verdopplung der vorangegangenen Zahl, wobei die Verdopplung durch die Ziffer der Rekursionstiefe getrennt wird. b) function zf(n: integer): string; begin if n<1 then zf:= '' else zf:= zf(n-1)+IntToStr(n)+zf(n-1); end; c) Integer-Zahlen sind auf den Zahlenbereich −215 .. +215−1 begrenzt. Selbst Longint-Zahlen (−231 .. +231−1) reichen als Zahlenbereich nicht aus. Also kann man die Ziffernfolge besser als Zeichenkette auffassen. Aufgabe 4: a) Es werden alle Wörter mit drei Buchstaben über dem Alphabet A..F gebildet. AAA, AAB, AAC, ... , AAF, ABA, ABB, ..., AFF, BAA, BAB, ..., FFF (insgesamt 63 Wörter). b) Procedure TF_Wortbildung.Permut(wort: string; n: integer); var i: integer; begin if n = length(wort) then Memo1.Lines.Add(wort) else for i:= n to length(wort) do begin Vertausche(wort[i], wort[k]); Permut(wort, n+1); end; end; { Sollte klar sein } Eine Lösung mit Verwendung des Mengentyps wäre wie folgt: type TZeichen = 'A'..'F'; TMZeichen = Set of TZeichen; ... procedure TF_Wortbildung.Permut(wort: string; n: Integer; MZeichen: TMZeichen); var i: TZeichen; begin if n=0 then M_Ausgabe.Lines.Add(wort) else for i:= 'A' to 'F' do if i in MZeichen then Permut(wort+i, n-1, MZeichen-[i]) end; Aufgabe 5: a) 10; 5+5; 5+2+2+1; 5+2+1+1+1; 5+1+1+1+1+1; 2+2+2+2+2; 2+2+2+2+1+1; 2+2+2+1+1+1+1; 2+2+1+1+1+1+1+1; 2+1+1+1+1+1+1+1+1; 1+1+1+1+1+1+1+1+1+1 b) const muenzen:array[1..5] of integer=(1,2,5,10,50); ... function Anzahl(b: integer; k: integer): integer; begin if k=1 then Anzahl:= 1 else if b<muenzen[k] then Anzahl:= Anzahl(b,k-1) else Anzahl:= Anzahl(b-muenzen[k],k) + Anzahl(b,k-1); end; c) Die Rekursionsanker sind jeweils unterstrichen. An diesen Stellen wird die Anzahl um 1 erhöht. Insgesamt 11 Rekursionsanker Anzahl = 11. Anzahl(10,5) A(10,4) A(0,4) + A(0,3) A(10,3) A(5,3) + A(0,2) A(0,3) + A(5,2) A(0,1) A(0,2) A(3,2) + A(0,1) A(10,2) A(8,2) + A(10,1) A(6,2) + A(8,1) A(1,2) + A(3,1) A(4,2) + A(6,1) A(1,1) A(2,2) + A(4,1) A(0,2) + A(2,1) A(5,1) A(0,1) d) procedure TF_Wechseln.Wechseln(b: Integer; k: integer; w: string); var i: integer; begin if b=0 then M_Ausgabe.Lines.Add(w) else begin if w<>'' then w:= w+'+'; for i:= k downto 1 do if b>=muenzen[i] then Wechseln(b-muenzen[i],i,w+IntToStr(muenzen[i])) end; end;