Algorithmische Grundlagen Sommersemester 2016 – VL02 Martin Mundhenk Uni Jena, Institut für Informatik 11. April 2016 1.2 Verzweigungen und Schleifen Die bisher betrachteten Programme bestanden aus Anweisungen, die der Reihe nach von der ersten bis zur letzten ausgeführt werden. Nun werden wir sehen, wie man diese Reihenfolge beeinflussen kann. Abhängig von Bedingungen können Anweisungs-Blöcke ausgeführt oder nicht ausgeführt werden (Verzweigungen), oder Anweisungs-Blöcke können mehrfach ausgeführt werden (Schleifen). Mittels Verzweigungen und Schleifen werden wir bereits viel mächtigere Programme schreiben können als bisher. 1.2.1 if-Anweisungen Viele Programme sollen bei verschiedenen Eingaben unterschiedlich arbeiten. Z.B. könnte das Programm teilen v2.py, das bei Eingabe zweier Werte a und b den Quotient und den Rest beim Teilen von a durch b berechnet, entweder 'Durch Null kann man nicht teilen!' ausgeben (falls b “ 0 ist) oder die gesuchten Werte ausgeben (falls b ‰ 0 ist). 1.2.2 Teilbarkeit überprüfen #------------------------------------------------------------------------# teilen_v3.py #------------------------------------------------------------------------import stdio, sys # Lies zwei Argumente a und b von der Kommandozeile. # Gib den (ganzzahligen) Quotienten und den Rest bei der Division von a durch b aus. a = int( sys.argv[1] ) b = int( sys.argv[2] ) if b == 0: stdio.writeln(’Durch Null darf man nicht teilen!’) else: stdio.write( str(a) + ’ geteilt durch ’ + str(b) + ’ ergibt ’ ) stdio.writeln( str( a//b ) + ’ Rest ’ + str( a%b ) + ’.’ ) #------------------------------------------------------------------------# python teilen_v3.py 1234 23 # 1234 geteilt durch 23 ergibt 53 Rest 15. # # python teilen_v3.py 1234 0 # Durch Null darf man nicht teilen! 1.2.3 Geschachtelte if-Anweisungen Bei der Lösung der quadratischen Gleichung a ¨ x 2 ` b ¨ x ` c “ 0 mittels der Formel ? ´b ˘ b 2 ´ 4 ¨ a ¨ c x1,2 “ 2¨a kann es 1. keine Lösung geben, da b 2 ´ 4 ¨ a ¨ c ă 0 oder a “ 0, 2. eine Lösung geben, da b 2 ´ 4 ¨ a ¨ c “ 0 und a ‰ 0, oder 3. zwei Lösungen geben, da b 2 ´ 4 ¨ a ¨ c ą 0 und a ‰ 0. 1.2.4 # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, falls sie import stdio, sys, math a = float( sys.agv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') else: if z==0: stdio.writeln( -b / (2*a) ) else: diskriminante = math.sqrt(b**2 - 4 * a * c) stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # 1.2.5 # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, falls sie import stdio, sys, math a = float( sys.agv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') elif z==0: stdio.writeln( -b / (2*a) ) else: diskriminante = math.sqrt(b**2 - 4 * a * c) stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, # falls sie existieren. import stdio, sys, math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') else: diskriminante = math.sqrt(z) if diskrimante > 0: stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, # falls sie existieren. import stdio, sys, math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') else: diskriminante = math.sqrt(z) if diskrimante > 0: stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # while-Schleifen Üblicherweise bestehen Programme aus Anweisungen, die häufig wiederholt werden. Die while-Schleife erlaubt die Wiederholung eines Anweisungs-Blocks, solange eine vorgegebene Bedingung erfüllt ist. 1.2.9 # Das Programm while-zaehler.py liest int-Wert a von der Kommandozeile ein # und gibt die Zahlen von 0 bis a aus. import stdio, sys a = int( sys.argv[1] ) zaehler = 0 while zaehler <= a: stdio.writeln(str(zaehler)) zaehler = zaehler + 1 #----------------------------# python while-zaehler.py 4 # 0 # 1 # 2 # 3 # 4 # 5 #----------------------------# python while-zaehler.py 9 # 0 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 1.2.10 # Das Programm alleteiler.py liest int-Wert a von der Kommandozeile ein # und gibt alle Teiler von a aus. import stdio, sys a = int( sys.argv[1] ) zaehler = 1 while zaehler <= a: if a%zaehler == 0: stdio.writeln(str(zaehler)) zaehler = zaehler + 1 #-----------------------------------------------------------------------------------# python alleteiler.py 8 # 1 # 2 # 4 # 8 1.2.11 #-----------------------------------------------------------# while_hochzaehlen.py # Gibt * mit größer werdendem Abstand zum linken Rand aus. #-----------------------------------------------------------import stdio n =12 i=0 while i<n: stdio.writeln(' '*i + '*') i = i+1 #-----------------------------------------------------------# python while_hochzaehlen.py # * # * # * # * # * # * # * # * # * # * # * # * 1.2.12 #------------------------------------------------------# zufallspfad.py # Gibt wiederholt * aus, dessen Abstand zum linken # Rand von Zeile zu Zeile # zufällig um -1,0,+1 verändert wird. #------------------------------------------------------import stdio, random i=0 abstand = 5 while i<20: abstand = abstand + random.randrange(-1,2) stdio.writeln(' '*abstand + '*') i = i+1 #-------------------------------------------------------- # python zufallspfad.py # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # Das Programm ganzlog.py liest int-Wert n von der Kommandozeile ein # und gibt den ganzzahligen Logarithmus von n zur Basis 2 aus. import stdio, sys n = int( sys.argv[1] ) ergebnis = 0 while n > 1: ergebnis = ergebnis + 1 n = n//2 stdio.writeln(str(ergebnis)) #-----------------------------------------------------------------------------------# python ganzlog.py 2016 # 10 # # python ganzlog.py 2048 # 11 # # python ganzlog.py 2047 # 10 # 1.2.14 # Das Programm ganzlog-trace.py liest int-Wert n von der Kommandozeile ein # und gibt den ganzzahligen Logarithmus von n zur Basis 2 aus. import stdio, sys n = int( sys.argv[1] ) ergebnis = 0 while n > 1: stdio.writeln('n ist ' + str(n) + ', ergebnis ist ' + str(ergebnis)) ergebnis = ergebnis + 1 n = n//2 stdio.writeln(str(ergebnis)) #-----------------------------------------------------------------------------------# python ganzlog-trace.py 538 n ist 538, ergebnis ist 0 n ist 269, ergebnis ist 1 n ist 134, ergebnis ist 2 n ist 67, ergebnis ist 3 n ist 33, ergebnis ist 4 n ist 16, ergebnis ist 5 n ist 8, ergebnis ist 6 n ist 4, ergebnis ist 7 n ist 2, ergebnis ist 8 9 1.2.15 # Das Programm zweierpotenz-w.py liest int-Werte n von der Kommandozeile ein # und gibt die 2erPotenzen 1,2,...,2^n aus. # falls sie existieren. import stdio, sys n = int( sys.argv[1] ) i = 0 potenz = 1 # der Zaehler fuer die Potenzen # die erste 2erPotenz ist 2^0 while i <= n: stdio.writeln(' 2 hoch ' + str(i) + ' ist ' + str(potenz) + '.') i = i + 1 potenz = potenz * 2 #--------------------------------------------------------------------------------# python zweierpotenz-w.py 5 # 2 hoch 0 ist 1. # 2 hoch 1 ist 2. # 2 hoch 2 ist 4. # 2 hoch 3 ist 8. # 2 hoch 4 ist 16. # 2 hoch 5 ist 32. 1.2.16 for-Schleifen Häufig wird in einer Schleife u.a. eine Variable hochgezählt und die Schleifen-Wiederholung endet, wenn ein bestimmter Wert erreicht wurde. Die for-Schleife erleichtert das Aufschreiben solcher Schleifen. 1.2.17 # Das Programm zweierpotenz-f.py liest int-Werte a von der Kommandozeile ein # und gibt die 2erPotenzen von 2^0, 2^1,...,2^n aus. import stdio, sys n = int( sys.argv[1] ) potenz = 1 # die erste 2erPotenz ist 2^0 for i in range(0,n+1): stdio.writeln(' 2 hoch ' + str(i) + ' ist ' + str(potenz) + '.') potenz = potenz * 2 #--------------------------------------------------------------------------------# python zweierpotenz-f.py 6 # 2 hoch 0 ist 1. # 2 hoch 1 ist 2. # 2 hoch 2 ist 4. # 2 hoch 3 ist 8. # 2 hoch 4 ist 16. # 2 hoch 5 ist 32. # 2 hoch 5 ist 64. 1.2.18 Simulation von Zufallsereignissen Zwei Würfel werden 24mal geworfen. Wie wahrscheinlich ist es, dass mindestens einmal dabei zwei 6en geworfen werden? Statt die Wahrscheinlichkeit exakt auszurechnen, simulieren wir das Experiment mit einem Programm. 1.2.19 #----------------------------------------------------------# zweiwuerfel.py #----------------------------------------------------------import stdio, sys, random erfolgszaehler = 0 for i in range(0,100000): # Zwei Würfel werden 24mal geworfen. # Das Spiel ist erfolgreich, wenn dabei ein Wurf aus zwei 6en gelingt. for i in range(24): if random.randrange(1,7)==6 and random.randrange(1,7)==6: erfolgszaehler +=1 break # Auswertung stdio.writeln(float(erfolg)/versuchszahl) #-----------------------------------------------------------# python zweiwuerfel.py # python zweiwuerfel.py # 0.49203 # 0.49133 # # # python zweiwuerfel.py # python zweiwuerfel.py # 0.49068 # 0.49023 # 17 und 4 Wir spielen 17+4 mit Würfeln. Zwei Spieler spielen. Jeder würfelt, ohne dass es der andere sehen kann. Ziel des Spiels ist es, den Wert 21 zu erreichen. Dazu würfelt der Spieler mit seinem Würfel und summiert die gewürfelten Zahlen. Man kann jederzeit aufhören zu würfeln. Das Ergebnis des Spielers ist seine Summe der gewürfelten Zahlen. Ein Spieler mit einem Ergebnis ą 21 hat verloren. Haben beide Spieler ein Ergebnis ď 21, dann gewinnt der Spieler mit dem höheren Ergebnis. Wir wollen ein Programm entwickeln, mit dem man eine gute Strategie für das Spiel finden kann. Zuerst schreiben wir ein Programm, das einen Spieler simuliert, der solange würfelt, bis er mindestens 21 erreicht hat. #----------------------------------------------------------------------------------# siebzehnundvier_1.py #----------------------------------------------------------------------------------import stdio, sys, random Wuerfelsumme = 0 while Wuerfelsumme<21: Wuerfelsumme = Wuerfelsumme + random.randrange(1,7) stdio.writeln('Wuerfelsumme ist ' + str(Wuerfelsumme)) stdio.writeln('Ergebnis: ' + str(Wuerfelsumme)) #-----------------------------------------------------------------------------------# python siebzehnundvier_1.py # Wuerfelsumme ist 5 # Wuerfelsumme ist 8 # Wuerfelsumme ist 10 # Wuerfelsumme ist 11 # Wuerfelsumme ist 15 # Wuerfelsumme ist 20 # Wuerfelsumme ist 21 # Ergebnis: 21 Eine Strategie ist es, nicht weiterzuwürfeln, wenn man 16 oder mehr erreicht hat. Dann hat man garantiert ein Ergebnis ď 21. #----------------------------------------------------------------------------------# siebzehnundvier_2.py #----------------------------------------------------------------------------------import stdio, sys, random Wuerfelsumme = 0 while Wuerfelsumme<=15: Wuerfelsumme = Wuerfelsumme + random.randrange(1,7) stdio.writeln('Wuerfelsumme ist ' + str(Wuerfelsumme)) stdio.writeln('Ergebnis: ' + str(Wuerfelsumme)) #-----------------------------------------------------------------------------------# python siebzehnundvier_2.py # Wuerfelsumme ist 6 # Wuerfelsumme ist 8 # Wuerfelsumme ist 10 # Wuerfelsumme ist 12 # Wuerfelsumme ist 16 1.2.23 Eine andere Strategie ist es, nicht weiterzuwürfeln, wenn man 17 oder mehr erreicht. Wenn man 16 erreicht hat, geht man ein kleines Risiko ein . . . #----------------------------------------------------------------------------------# siebzehnundvier_3.py #----------------------------------------------------------------------------------import stdio, sys, random Wuerfelsumme = 0 while Wuerfelsumme<=16: Wuerfelsumme = Wuerfelsumme + random.randrange(1,7) stdio.writeln('Wuerfelsumme ist ' + str(Wuerfelsumme)) stdio.writeln('Ergebnis: ' + str(Wuerfelsumme)) #-----------------------------------------------------------------------------------# python siebzehnundvier_3.py # Wuerfelsumme ist 2 # Wuerfelsumme ist 4 # Wuerfelsumme ist 7 # Wuerfelsumme ist 10 # Wuerfelsumme ist 14 # Wuerfelsumme ist 16 # Wuerfelsumme ist 22 # Ergebnis: 22 1.2.24 Welche der beiden Strategien ist besser? Wir wollen das experimentell überprüfen. Dafür lassen wir zwei Spieler mit den beiden Strategien gegeneinander spielen und schauen nach, wer gewinnt. #----------------------------------------------------------------------------------# siebzehnundvier_4.py #----------------------------------------------------------------------------------import stdio, sys, random # Spieler 1 spielt mit seiner Strategie. Wuerfelsumme1 = 0 while Wuerfelsumme1<=15: Wuerfelsumme1 = Wuerfelsumme1 + random.randrange(1,7) # Spieler 2 spielt mit seiner Strategie. Wuerfelsumme2 = 0 while Wuerfelsumme2<=16: Wuerfelsumme2 = Wuerfelsumme2 + random.randrange(1,7) # Der Gewinner wird bestimmt. if Wuerfelsumme1<=21 and ( Wuerfelsumme2>21 or Wuerfelsumme1>Wuerfelsumme2): stdio.writeln('Spieler 1 gewinnt.') elif Wuerfelsumme2<=21 and ( Wuerfelsumme1>21 or Wuerfelsumme2>Wuerfelsumme1): stdio.writeln('Spieler 2 gewinnt.') 1.2.25 Schließlich lassen wir die Spieler 100000mal gegeneinander spielen, und zählen, wie oft jeder gewinnt. 1.2.26 # Wir benutzen zwei Zähler für die Gewinne jedes Spielers. gewinne1 = 0 gewinne2 = 0 # Wir lassen die beiden Spieler 1000000 Spiele spielen. for i in range(100000): # Spieler 1 spielt mit seiner Strategie. Wuerfelsumme1 = 0 while Wuerfelsumme1<=15: Wuerfelsumme1 = Wuerfelsumme1 + random.randrange(1,7) # Spieler 2 spielt mit seiner Strategie. Wuerfelsumme2 = 0 while Wuerfelsumme2<=16: Wuerfelsumme2 = Wuerfelsumme2 + random.randrange(1,7) # Der Gewinner wird bestimmt und sein Gewinn-Zähler wird um 1 erhöht. if Wuerfelsumme1<=21 and ( Wuerfelsumme2>21 or Wuerfelsumme1>Wuerfelsumme2): gewinne1 = gewinne1 + 1 elif Wuerfelsumme2<=21 and ( Wuerfelsumme1>21 or Wuerfelsumme2>Wuerfelsumme1): gewinne2 = gewinne2 + 1 # Gib aus, wer öfter gewonnen hat. if gewinne1>gewinne2: stdio.writeln('Spieler 1 hat ' + str(gewinne1-gewinne2) + 'mal oefter gewonnen als Spieler 2.') else: stdio.writeln('Spieler 2 hat ' + str(gewinne2-gewinne1) + 'mal oefter gewonnen als Spieler 1.') #----------------------------------------------------------------------------------------------# python siebzehnundvier_5.py # Spieler 2 hat 26584mal oefter gewonnen als Spieler 1. 1.2.27 Zusammenfassung § Wir haben if-Anweisungen, while-Schleifen und for-Schleifen kennengelernt. § Wir kennen die Strukturierung von Programmen in Anweisungs-Blöcke. § Wir können einfache Programme mit Eingabe von Argumenten Abarbeitung von Anweisungs-Blöcken, die in Schleifen wiederholt oder durch if-Anweisungen ausgeführt oder übersprungen werden Ausgabe von Ergebnissen schreiben und deren Ausführung nachvollziehen.