05.11.2013 Aufrufe

Iterative und Rekursive Algorithmen Iteration und Rekursion sind im ...

Iterative und Rekursive Algorithmen Iteration und Rekursion sind im ...

Iterative und Rekursive Algorithmen Iteration und Rekursion sind im ...

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

© J. Rau Januar 2013<br />

<strong>Iterative</strong> <strong>und</strong> <strong>Rekursive</strong> <strong>Algorithmen</strong><br />

<strong>Iteration</strong> <strong>und</strong> <strong>Rekursion</strong> <strong>sind</strong> <strong>im</strong> Prinzip gleichwertig - sie sorgen für das mehrmaliges Ausführen einer Aktion.<br />

<strong>Rekursive</strong> <strong>Algorithmen</strong> <strong>sind</strong> aber häufig kürzer <strong>und</strong> eleganter, dafür benötigen sie während ihrer Laufzeit mehr<br />

Arbeitsspeicher.<br />

Ein iterativer Algorithmus wiederholt die Aktion, indem sie einen Zähler benutzt, der angibt wie oft die<br />

Aktion ausgeführt werden soll.<br />

<strong>Iteration</strong>en werden durch die bekannten Schleifenstrukturen for ( ) { } <strong>und</strong> while ( ) { } programmiert.<br />

<strong>Iterative</strong> Methode PizzaEssen ( )<br />

for (ersten bis letzten Bissen ; n<strong>im</strong>m den nächsten Bissen) {Schneide diesen Bissen ab <strong>und</strong> iss ihn auf };<br />

Unter <strong>Rekursion</strong> versteht man ebenfalls eine wiederholte Ausführung, doch ohne Zählschleife, stattdessen ruft<br />

sich die Aktion (bis zu einer Abbruchbedingung) <strong>im</strong>mer wieder selbst auf <strong>und</strong> nutzt dafür die<br />

Entscheidungsstruktur if( ) { } else { }.<br />

<strong>Rekursive</strong> Methode Pizzaessen ( ):<br />

if (Teller nicht leer) {Schneide einen Bissen ab <strong>und</strong> iss ihn auf; PizzaEssen ( );} else {fertig;};<br />

Ein Algorithmus heißt rekursiv, wenn mindestens einer seiner Schritte darin besteht, den gleichen Algorithmus<br />

für einfachere Anfangswerte auszuführen. Man erkennt die <strong>Rekursion</strong> daran, dass sich die Methode selbst<br />

aufruft. Jeder rekursive Algorithmus muss eine Abbruchbedingung enthalten.<br />

Kennen Sie Matroschkas ? Sie <strong>sind</strong> ein typisches Anschauungsmodell für <strong>Rekursion</strong>:<br />

Methode matroschkaAuspacken (Puppe P):<br />

if ( P zu öffnen geht) { Packe P aus <strong>und</strong> entn<strong>im</strong>m den Inhalt von P‘; matroschkaAuspacken (P‘);}<br />

else { n<strong>im</strong>m P freue dich du hast die ganz Kleine [Ende]}<br />

Damit ein Problem eine rekursive Lösung hat, muss es folgende Eigenschaften besitzen:<br />

<br />

<br />

<br />

Das Originalproblem muss sich in einfachere Varianten von sich selbst zerlegen lassen.<br />

Die Zerlegung in Teilprobleme muss zuletzt auf so einfache Varianten des Originalproblems führen, dass<br />

sie ohne weitere Zerlegung gelöst werden können.<br />

Wenn alle Teilprobleme gelöst <strong>sind</strong>, müssen die Lösungen so zusammengesetzt werden können, dass sich<br />

eine Lösung des Originalproblems ergibt.


© J. Rau Januar 2013<br />

Vergleich von <strong>Rekursion</strong> <strong>und</strong> <strong>Iteration</strong><br />

<strong>Iteration</strong> ist die Wiederholung<br />

strukturgleicher Blöcke durch Aneinanderreihung<br />

<strong>Rekursion</strong> ist die Wiederholung strukturgleicher<br />

Blöcke durch Schachtelung<br />

<strong>Iteration</strong> (Endrekursion):<br />

Man öffnet die größte Puppe, entn<strong>im</strong>mt die<br />

kleinere Puppe <strong>und</strong> setzt die beiden Teile der<br />

größeren Puppe wieder zusammen. Dies wiederholt<br />

man, bis die kleinste Puppe ausgepackt ist.<br />

Echte <strong>Rekursion</strong>:<br />

Man öffnet nacheinander jede Puppe, stellt deren 2<br />

Teile geöffnet ab <strong>und</strong> entn<strong>im</strong>mt die nächste Puppe.<br />

Wenn die kleinste Puppe entnommen wurde, setzt man<br />

die jeweiligen zwei Teile der größeren Puppen in<br />

umgekehrter Reihenfolge zusammen.<br />

<strong>Rekursive</strong> <strong>Algorithmen</strong> <strong>sind</strong> oft besonders gut zur Problemlösung geeignet, da<br />

(1) sie sehr mächtig <strong>und</strong> kompakt darstellbar <strong>sind</strong>,<br />

(2) sie sich relativ leicht finden lassen,<br />

(3) sich ihre Korrektheit relativ leicht zeigen lässt.<br />

Der Nachteil ist, dass rekursive <strong>Algorithmen</strong> evtl. viel Speicherplatz <strong>und</strong> Rechenzeit erfordern.<br />

Beispiele<br />

Berechnung des größten gemeinsamen Teilers zweier Zahlen (ggT)<br />

iterativer Algorithmus itggT(int m,int n):<br />

Speichere m <strong>und</strong> n unter den Namen x <strong>und</strong> y.<br />

Schritt 1: while ( x! = y), else { gehe zu Schritt 2};<br />

Schritt 2: if ( x > y) { x =(x-y) <strong>und</strong> gehe zu Schritt 1};<br />

if ( x < y) { y= (y-x) <strong>und</strong> gehe zu Schritt 1};<br />

{ liefere x als Ergebnis ab };<br />

Flussdiagramme für ggT in Java Beispiel ggT 84 <strong>und</strong> 30<br />

Minus<br />

Minus<br />

Minus<br />

Gleich


© J. Rau Januar 2013<br />

Die Wiederholung des Algorithmus ab Schritt 2 in der <strong>Iteration</strong> wird durch <strong>Rekursion</strong> ersetzt.<br />

rekursiver Algorithmus rekggT (int m,int n):<br />

Schritt 1: if ( m == n) {liefere m als Ergebnis, sonst gehe zu Schritt 2};<br />

Schritt 2: if ( m > n) {liefere das Ergebnis von rggT ( (m-n), n) als Ergebnis ab} else {gehe zu Schritt 3};<br />

Schritt 3:<br />

if ( m < n) {liefere das Ergebnis von rggT ( m, (n-m) ) als Resultat ab};<br />

ggT mit BlueJ (iterativ)<br />

public void itggT (int m, int n) {<br />

int x = m;<br />

int y = n;<br />

int z;<br />

while (x!= y) {<br />

z = x;<br />

if (x > y) { x = x - y; }<br />

else { y = y - x; }; };<br />

System.out.println (“Der ggT ist: ”+z); }<br />

ggT mit BlueJ (rekursiv)<br />

public int rekggT (int m, int n) {<br />

}<br />

if (m == n) { return m; }<br />

if (m > n) { return rekggT (m-n, n); }<br />

else { return rekggT(m, n-m); }<br />

public void ausgabeggT (int m, int n) {<br />

int z = rekggT (m,n);<br />

System.out.println (“Der ggT ist: ”+z); }<br />

Fibonacci-Folge <strong>und</strong> weitere Beispiele Fakultät, Quersumme<br />

1) Hinter den Ziffernfolgen 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377... verbirgt sich ein<br />

interessantes rekursives Bildungsgesetz: die Folge von Fibonacci. <br />

( n 1) Fib( n 2) für n > 2<br />

Fib( n)<br />

<br />

1 für 0


© J. Rau Januar 2013<br />

2) Eine rekursive Methode fakultät(int n) berechnet die Fakultät einer positiven ganzen Zahl n.<br />

public int fak (int n) {<br />

if (n > 1) { return n * fak (n- 1); }<br />

else { return 1; }<br />

}<br />

3) Was berechnen die <strong>Algorithmen</strong>, die durch die folgenden Quelltexte dargestellt werden ?<br />

public int irgendwas ( int p, int q ){<br />

if ( p == 0 ) { return 0; } else { return q*irgendwas ( p-1, q ); }; }<br />

public int irgendwas ( int p ){<br />

if ( p == 1 ) { return 1; } else { return p + irgendwas ( p-1 ); }; }<br />

4) Die Methode int querSumme(int zahl) berechnet die Quersumme einer pos. Ganzzahl zahl.<br />

Hinweise: Beispiel: zahl=345 von hinten mit der Zerlegung beginnen:<br />

letzte Ziffer x= zahl modulo 10 5<br />

vorletzte Ziffer a= zahl modulo 100 45<br />

y= (a-x):10 40:10=4<br />

erste Ziffer b= zahl modulo 1000 345<br />

oder einfach die Zahl nehmen<br />

z= (b-a-x):100 300:100=3<br />

Quersumme:<br />

qs=x+y+z<br />

Lässt sich beliebig erweitern für 4 stellige... usw.<br />

x= (zahl modulo10-zahl modulo1) :1<br />

y= (zahl modulo100-zahl modulo10) :10<br />

z= (zahl modulo1000-zahl modulo100-zahl modulo10) :100 ...<br />

Beispiel:zahl= 3456<br />

1.DL qs=6 (3456-(3456%10)):10=345<br />

2.DL qs=5+6 (345-(345%10)):10=34<br />

3.DL qs=4+5+6 (34-(34%10)):10=3<br />

4.DL qs=3+4+5+6 (3-(3%10)):10=0<br />

public int querIterativ (int zahl) {<br />

int qs;<br />

while (zahl>0) {<br />

qs=qs+(zahl%10);<br />

zahl=((zahl –(zahl % 10)) /10);<br />

}<br />

return qs; }<br />

//iterativ<br />

public int querRekursiv (int zahl) { //rekursiv<br />

if (zahl>0) {<br />

qs=querRekursiv((zahl-(zahl%10))/10)+zahl%10<br />

;}<br />

return qs; }

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!