Algorithmen und Programmierung – Iterationen 4.1 Einführung Algorithmen und Programmierung Wintersemester 2016/2017 4.1 Einführung Motivierendes Beispiel „Aufgabe“ Esse alle Pralinen in einer Pralinenschachtel! Algorithmen und Programmierung Annahme: Ich weiß, wie ich eine Praline essen kann. 4. Kapitel Iterationen Prof. Matthias Werner Professur Betriebssysteme Bildquelle: BeautifulCataya, CC 2.0 WS 2016/17 · M. Werner Algorithmen und Programmierung – Iterationen 4.1 Einführung osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.1 Einführung Variante 1 Variante 2 Esse die erste Praline von links in der ersten Reihe. Esse die zweite Praline von links in der ersten Reihe. .. . Esse die Praline ganz rechts in der ersten Reihe. Esse die erste Praline von links in der zweiten Reihe. .. . Esse die erste Praline von links in der letzten Reihe. Esse die zweite Praline von links in der letzten Reihe. .. . I Esse die Praline ganz rechts in der letzten Reihe. I 2 / 31 I Weise den Pralinen die Nummern 1 bis n zu I Zähle von 1 bis n und esse die Praline mit der jeweiligen Nummer Anmerkung: Es findet eine Abbildung von der Menge der natürlichen Zahlen N auf die Menge der Pralinen statt Problem: Algorithmus1 ist evtl. sehr lang 1 Genau genommen ist es in der dargestellten Form gar kein Algorithmus; vgl. Kapitel 1. WS 2016/17 · M. Werner 3 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner 4 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.1 Einführung Algorithmen und Programmierung – Iterationen 4.1 Einführung Variante 3 Variante 4 I Zähle die Pralinen á n I Zähle von 1 bis n und esse bei jeder Zahl jeweils eine Praline I I I Anmerkung: Der Vorgang des Essens wird für eine vorher bestimme Zahl von Wiederholungen durchgeführt WS 2016/17 · M. Werner 5 / 31 osg.informatik.tu-chemnitz.de Anmerkung: Der Vorgang des Essens wird für eine (zunächst) unbestimme Zahl von Wiederholungen durchgeführt WS 2016/17 · M. Werner Algorithmen und Programmierung – Iterationen 4.1 Einführung 6 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Unterschiedliche Sichtweisen I Solange noch eine Praline da ist: Esse eine (beliebige) Praline 4.2 Schleifen in C und Python Wiederholen... I ...für eine bestimmte Anzahl von Wiederholungen I ...für Elemente einer Menge I ...solange eine Bedingung (nicht) erfüllt ist I In C gibt es drei Arten von Schleifen: I while-Schleife I do-while-Schleife I for-Schleife I I Alle Varianten sind aufeinander abbildbar I Solche Wiederholungen heißen in Programmiersprachen Schleifen I Alle Schleifen nutzen Bedingungen Jede davon kann2 die anderen simulieren I Schleifen gibt es in vielen (nicht allen!) Programmiersprachen I Welche genutzt wird, ist also z.T. Geschmackssache I Allgemein gibt es bei Schleifen immer etwas Invariantes/Konstantes und i.d.R. etwas sich Änderndes 2 ...ggf unter Nutzung anderer Sprachkonstrukte... WS 2016/17 · M. Werner 7 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner 8 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python while-Schleife (Forts.) while-Schleife I Die while-Schleife führt ein Statement solange aus, wie eine Bedingung wahr ist. I Sie arbeitet wie folgt: 1. Es wird überprüft, ob der Ausdruck in der Klammer nach dem Schlüsselwort while eingehalten wird Beispiele: / * sqr . c -- Heron ’s method * / # include < stdlib .h > # include < math .h > # include < stdio .h > 2. Falls ja, wird eine Anweisung nach diesem Ausdruck ausgeführt (á Schleifenkörper) und anschließen wieder zu 1. gesprungen I Wenn die Schleife mehrere Anweisungen umfassen soll, müssen diese in einem Block geklammert werden # include < stdio .h > int main () { int i =3; while (i >0) { printf (" Cthulhu !\ n" ); i=i -1; } return 0; } int main ( int argc , char ** args ) { double x =1.0; double y= atof ( args [1]); 3. Falls nein, wird mit der ersten Anweisung nach dem Schleifenkörper fortgesetzt Anweisung (Schleifenkörper) while ( fabs (y -x * x ) >0.00001){ x =0.5 * ( x+y/x ); } printf ( " sqrt (% f) = %f .\ n" ,y ,x ); return 0; } while(i<10) i=i+1; Bedingung WS 2016/17 · M. Werner 9 / 31 WS 2016/17 · M. Werner osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python do-while-Schleife Schleifen können zur Bearbeitung oder Belegung der Elemente eines Array zur Laufzeit genutzt werden # include < stdio .h > enum { arraysize =12}; / * constant for array size * / I Die do-while-Schleife ähnelt der while-Schleife I Unterschied: Die Bedingung wird nach einem Schleifenduchlauf geprüft I Damit der Compiler weiß, dass eine Schleife beginnt, wird zu Schleifenbeginn das Schlüsselwort do gesetzt int main () { int xa [ arraysize ], i =0; while (i < arraysize ){ xa [ i ]= i * i; i = i +1; } osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Schleifen und Felder I 10 / 31 do i=i+1; while(i<10); / * 0 ,1 ,... ,11 */ / * square of index * / Schleifenkörper i =0; while (i < arraysize ){ / * 0 ,1 ,... ,11 */ printf ( " Element %d of xa : % d \ n " ,i , xa [ i ]); i = i +1; } return 0; Bedingung I Wieder müssen bei mehr als einer Anweisung im Schleifenkörper diese in geschweifte Klammern gesetzt werden I do-while-Schleife werden immer dann eingesetzt, wenn der Schleifenkörper mindestens einmal ausgeführt werden soll } WS 2016/17 · M. Werner 11 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner 12 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Beispiele für for-Schleife for-Schleife I Typisch: I Vor einer Schleife wird ein Wert initialisiert I Im Schleifenkörper wird ein (meist derselbe) Wert geändert I Die for-Schleife lässt beides explizit in der Schleifendeklaration zu I Wieder: Mehr als ein Statement im Schleifenkörper muss geklammert werden Achtung: Der Schleifenkörper kann leer sein á einzelnes Semikolon I Schleifenkörper im Schleifenkopf integriert I Schlechter Stil, außer bei sehr einfachen Schleifen Initialisierung / * for .c -- loop with for * / # include < stdio .h > int main ( int argc , char * argv []){ for ( int i =0; i < argc ; i=i +1) printf ("%d. argument : %s\n" ,i +1 , argv [i ]); return 0; } I for(int i=0;i<10; i=i+1) printf("i=%d \n",i); Bedingung Schleifenkörper nach Schleifenkörper WS 2016/17 · M. Werner 13 / 31 > ./for 23 foo Bar 42 1. argument: ./for 2. argument: 23 3. argument: foo 4. argument: Bar 5. argument: 42 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Es können einzelne Ausdrücke weggelassen werden... I break und continue ... oder auch alle Ausdrücke á Endlosschleife / * for2 . c -- loop with for , #2 * / # include < stdio .h > / * for - ever .c -- infinite loop * / # include < stdio .h > int main ( int argc , char * argv []){ int i =0; for (; i < argc ; i = i +1) printf ( " % d . argument : % s \ n " , i +1 , argv [ i ]); int main (){ for (;;) printf (" The answer is 42.\ n" ); return 0; // never reached } return 0; I Schleifen werden solange durchlaufen, wie die Schleifenbedingung gegeben ist I Allerdings gibt es zwei Möglichkeiten, innerhalb des Schleifenkörpers den Kontrollfluss zu ändern: break: Beendet die Schleife unabhängig von der Schleifenbedingung continue: Startet sofort die nächste Auswertung der Schleifenbedingung und ggf. den nächsten Schleifendurchlauf Achtung! Die Benutzung von break und continue ist eigentlich nicht notwendig und ein Indiz, dass die Programmlogik nicht hinreichend durchdacht wurde. Daher sollten break und continue nur zur Behandlung von Notfällen (Ausnahmen) genutzt werden. } WS 2016/17 · M. Werner osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Beispiele für for-Schleife (Forts.) I 14 / 31 15 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner 16 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python break und continue (Forts.) Geschachtelte Schleifen / * reciprocal . c -- calculate reciprocal value of array elements * / # include < stdio .h > I Schleifen können auch ineinander verschachtelt sein I Dabei können sich die Schleifen auch beeinflussen / * a negative value indicates end of list * / double f []={1.0 , .5 , 3.1415 , .33333 , 0.0 , 2.7182 , 42.23 , -1}; / * for3 .c -- nested loops * / # include < stdio .h > int main () { int i ; for ( i =0; ; i = i +1){ if (f [i ] <0.0) break ; if (f [i ] <=0.0001) continue ; f [ i ]=1/ f [ i ]; } int main ( int argc , char * argv []){ int goal ; if ( sscanf ( argv [1] , "%d" ,& goal )!=1) return -1; for ( int i =1; i <= goal ; i=i +1) { for ( int j =1; j <= i; j=j +1) printf ("%d " ,i ); printf ( "\n" ); } return 0; for ( i =0; f [ i ] >=0.0; i = i +1) printf ( " % d value : % f \ n " ,i , f [ i ]); return 0; } } WS 2016/17 · M. Werner 17 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python I Schleifensteuerung In Python gibt es zwei Arten von Schleifen: I while-Schleifen I for-Schleifen I Auch Python kennt die Schlüsselwörter break und continue I Die Semantik ist gleich zu C I Zusätzlich gibt es bei Python-Schleifen einen optionalen else-Zweig á Wird nach der Schleife ausgeführt, wenn diese nicht abgebrochen wurde while-Schleifen ähneln ihren Pendants in C: i =10 while (i >0): print (" i= " ,i) i =i -1 I osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Schleifen in Python I 18 / 31 Wie immer in Python können Blöcke durch Einrückungen markiert werden WS 2016/17 · M. Werner 19 / 31 osg.informatik.tu-chemnitz.de def prim ( x ): y= int (x /2) while y >=2: if x % y == 0: print (x , " has factor " , y) break y =y -1 else : print (x , " is prim ") WS 2016/17 · M. Werner 20 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Schleifensteuerung (Forts.) for-Schleife in Python Die Syntax for-Schleife sieht zunächst ähnlich wie die while-Schleife aus I I Mit Hilfe von break kann leicht die do-while-Schleife aus C nachempfunden werden for i in C: do _ something (i) i =0 while True : print (" i= " ,i) i = i +1 if not (i <10): break print ( " Ende " ) Die Semantik ist jedoch anders: I C muss eine Sequenz oder Menge sein (d.h. String, Liste, Tupel, Menge, Dictionary)3 I Es werden i nacheinander die Elemente von C zugewiesen I 3 Genauer: Es muss ein iterierbarer Typ sein. WS 2016/17 · M. Werner 21 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python for-Schleife in Python (Forts.) for-Schleife in Python (Forts.) Um die Semantik der C-for-Schleife nachzuempfinden, kann die range-Funktion genutzt werden I # for . py -- loops over sequence objects for x in [ ’ John ’ , ’ Paul ’ ,’ Georg ’ , ’ Pete ’ ]: print (x ) I 22 / 31 range(start=0, end, step=1 ) Dies funktioniert auch für gemischte Typen: Von Bis (nicht einschliesslich) Schrittweite »> range(5), range(2,5), range(2,10,2) ([0, 1, 2, 3, 4], [2, 3, 4], [2, 4, 6, 8]) »> # for2 . py -- mixed types T =( ’ Alpha ’ ,2 ,(1 ,2)) for x in T : print (2 * x) # for3 . py -- loops with range python for2.py AlphaAlpha 4 (1, 2, 1, 2) WS 2016/17 · M. Werner for i in range (1 ,8): for j in range (i ): print (i , end = ’ ’) print () 23 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner 24 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.2 Schleifen in C und Python Algorithmen und Programmierung – Iterationen 4.3 Iteration und Rekursion Iteratoren in C I I Umgekehrt kann man auch den Python-Ansatz in C „nachempfinden“ Solche Iteratoren sind z.B. in C++ verbreitet á Dort aber eleganter (auch in C geht es schöner ) 4.3 Iteration und Rekursion / * iter . c -- iterator with C * / # include < stdlib .h > # include < stdio .h > I Bisher wurden in Schleifen immer (implizite) Zuweisungen benutzt á Zustandsmodell I Auch im funktionalen Modell sind Schleifen möglich Dort werden sie durch Rekursion realisiert I static int ndx =0; char * first () { return names [ ndx =0]; } char * next (){ if ( names [ ndx ]== NULL ) ndx =0; else ndx = ndx +1; return names [ ndx ]; } / * recursion .c -- loops by recursion * / # include < stdio .h > void say _ it ( int i ){ if (i ==0) return ; else { printf ( " Cthulhu !\ n" ); say _ it (i -1); } } char * names []={ " John " ," Paul " ," Georg " , " Ringo " , NULL }; int main (){ for ( char * str = first (); str != NULL ; str = next ()) printf ( " %s " , str ); return 0; } WS 2016/17 · M. Werner 25 / 31 int main (){ say _ it (3); return 0; } osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner Algorithmen und Programmierung – Iterationen 4.3 Iteration und Rekursion I Dabei kann der Schleifenkörper von der „Schleifenmechanik“ getrennt werden, so dass eine Schleifenfunktion möglich ist Wir nutzen hier einen Zeiger auf Funktionen Schleifenfunktion (Forts.) I / * loop - func . c * / # include < stdio .h > Allgemeiner (und in der Anwendung eleganter) funktioniert dies in Python, das mit λ-Funktionen (namenlosen Funktionen) ein Feature funktionaler Sprachen bietet // Pointer to a void function with integer argument typedef void ( * VFP )( int ); void loop ( VFP func , int start , int end , unsigned int step ){ if ( start <= end ) { func ( start ); loop ( func , start + step , end , step ); } } void lbody ( int param ){ printf ( " % d ^2=% d \ n " , param , param * param ); } int main (){ loop ( lbody ,0 ,10 ,1); return 0; } WS 2016/17 · M. Werner osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.3 Iteration und Rekursion Schleifenfunktion I 26 / 31 27 / 31 osg.informatik.tu-chemnitz.de # loop - func . py -- loops by recursion from sys import stdout loop = lambda v ,e ,i ,f , args : \ e (v) and (f ( * (( v ,)+ args )) , \ loop (( lambda y: y+i )( v),e ,i ,f , args )) or 0 def printpow (i ,x ): print (i ," ** " ,x ,"=" ,i ** x) >python loop-func.py 1 ** 2 = 1 2 ** 2 = 4 3 ** 2 = 9 4 ** 2 = 16 [10] [9] [8] [7] [6] [5] [4] [3] [2] [1] [0]> def printi (i ,b ,a ): stdout . write (b+ str (i )+ a) loop (1 , lambda x: x <=4 ,1 , printpow ,(2 ,)) loop (10 , lambda x: x >=0 , -1 , printi , ("[" ,"] " )) WS 2016/17 · M. Werner 28 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen 4.3 Iteration und Rekursion Algorithmen und Programmierung – Iterationen 4.3 Iteration und Rekursion Äquivalenz I Äquivalenz (Forts.) Allgemein gilt: Jede Schleife in einem Programm kann in eine rekursive Funktion umgewandelt werden. I Schleifen und Rekursion sind also für die meisten praktischen Anwendungsfälle gleichmächtig I In der Regel ist eine Schleife übersichtlicher I Es gibt aber auch Fälle (vgl. Kapitel 9), in denen Rekursion die handlichere Lösung bildet I Einige Programmiersprachen kennen keine Schleifen, sondern nur Rekursionen und Jede (trivial-)rekursive Funktion kann mit Hilfe von Schleifen berechnet werden.Genauer: Primitiv-rekursive Funktionen lassen sich stets mit a priori beschränkten Schleifen berechnen; bei sogenannten µ-rekursive Funktionen muss diese Einschränkung aufgegeben werden. I Nicht trivialerekursiv ist z.B. die ACKERMANN-Funktion: f (x, y) = ⇐x=0 y + 1 f (x − 1, 1) ⇐ (x 6= 0) ∧ (y = 0) f (x − 1, f (x, y − 1)) sonst WS 2016/17 · M. Werner 29 / 31 osg.informatik.tu-chemnitz.de Algorithmen und Programmierung – Iterationen Aufgaben Aufgaben Aufgabe 4.1 Was bedeutet in C die folgende Deklaration: int* (*foo)(int,int*) Aufgabe 4.2 In einer Schale und in einem Eimer seien eine Anzahl von weißen und orangen Tischtennisbällen, wobei soviel Bälle im Eimer sind, dass der folgende Algorithmus stets durchgeführt werden kann: 1. Nehme zwei beliebige Bälle aus der Schale. I I Wenn sie die gleiche Farbe haben, werfe sie in den Eimer und nehme einen orangen Ball aus dem Eimer und lege ihn in die Schale. Wenn sie unterschiedliche Farbe haben, lege den weißen in die Schale zurück und werfe den orangen Ball in den Eimer. 2. Wiederhole, bis nur noch ein Ball in der Schale ist. Wird tatsächlich stets ein Ball übrig bleiben? Wenn ja, kann etwas über seine Farbe in Abhängigkeit zur ursprünglichen Anzahl der Bälle gesagt werden? Wenn ja, was? WS 2016/17 · M. Werner 31 / 31 osg.informatik.tu-chemnitz.de WS 2016/17 · M. Werner 30 / 31 osg.informatik.tu-chemnitz.de