Algorithmische Grundlagen – Einführung in das Programmieren mit Python (Teil 1) Sommersemester 2017 Martin Mundhenk Uni Jena, Institut für Informatik 3. April 2017 Vorlesung Algorithmische Grundlagen (Sommer 2017) Die Vorlesung/Übung orientiert sich am Buch Introduction to Programming in Python – An Interdisciplinary Approach von Robert Sedgewick, Kevin Wayne und Robert Dondero (Addison Wesley, 2015) Auch die Webseite zum Buch http://introcs.cs.princeton.edu/python/home/ ist für diese Vorlesung nützlich. Organisatorisches http://tinyurl.com/AlgorithmischeGrundlagen § § Vorlesung montags, 16-18 Uhr, Raum 3325, Ernst-Abbe-Platz 2. Übung donnerstags, 8-10 Uhr, Raum 3410 (Linux-Pool 2), EAP2. Zur Teilnahme brauchen Sie eine Nutzerkennung beim FRZ! (FRZ: Fakultätsrechenzentrum der Fakultät für Mathematik und Informatik, EAP2, 4.Stock) § Es gibt ein wöchentliches Übungsblatt (ca. 12). Abgabe ist montags 16 Uhr (an [email protected]). § Zur Zulassung zur Modulprüfung müssen jeweils mindestens 50% der Punkte der Übungsblätter aus der ersten und der zweiten Semesterhälfte erreicht sein. Die Abschlussprüfung ist mündlich und dauert ca. 30 Minuten. Sie besteht aus der Vorstellung eines Programmierprojekts. Alle Dateien dazu müssen bis spätestens 30 Stunden vor Beginn der Prüfung per Email bei mir angekommen sein ([email protected]). Prüfungstermine sind ab August und werden noch bekannt gegeben. § Inhaltsverzeichnis 1. Elemente des Programmierens 2. Funktionen und Module 4. Algorithmen 5. Abschlussprojekte (und Anmerkungen dazu) Die Nummerierung der Kapitel 1, 2 und 4 entspricht der Nummerierung im Buch von Sedgewick et al. 0.0.4 1 Elemente des Programmierens Ein Programm zu schreiben ist nicht schwieriger, als einen Aufsatz zu schreiben. Wir schauen uns die Grundbausteine von Programmen der Programmiersprache Python an und starten mit dem Programmieren. 1. Elemente des Programmierens 1.2 Grundlegende Daten-Typen 1.3 Verzweigungen und Schleifen 1.4 Arrays 1.5 Ein- und Ausgabe 1.6 Page Rank 1.2 Grundlegende Datentypen Beim Programmieren geht es um den Umgang mit Daten. Die elementaren Arten von Daten beim Programmieren mit Python sind § Zahlen, § Texte und § Wahrheitswerte. Für sie sind jeweils unterschiedliche Operationen verfügbar (und sie werden intern unterschiedlich behandelt). 1.2.1 Ein erstes Beispiel #----------------------------------------------------------------# oberflaeche.py #----------------------------------------------------------------# Berechne das Volumen und die Oberfläche eines Quaders. # Zuerst werden die Maße des Quaders angegeben. Hoehe = 5 Breite = 12 Tiefe = 32 # Daraus können nach den bekannten Formeln # das Volumen und die Oberfläche berechnet werden. Volumen = Hoehe * Breite * Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) # Die berechneten Werte werden ausgegeben. print(Volumen) print(Oberflaeche) 1.2.2 Ein erstes Beispiel #----------------------------------------------------------------# oberflaeche.py #----------------------------------------------------------------# Berechne das Volumen und die Oberfläche eines Quaders. # Zuerst werden die Maße des Quaders angegeben. Hoehe = 5 Breite = 12 Tiefe = 32 # Daraus können nach den bekannten Formeln # das Volumen und die Oberfläche berechnet werden. Volumen = Hoehe * Breite * Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) # Die berechneten Werte werden ausgegeben. print(Volumen) print(Oberflaeche) Kommentar beginnt mit #“. Von dort ab wird die Zeile ignoriert. ” 1.2.2 Ein erstes Beispiel #----------------------------------------------------------------# oberflaeche.py #----------------------------------------------------------------# Berechne das Volumen und die Oberfläche eines Quaders. # Zuerst werden die Maße des Quaders angegeben. Hoehe = 5 Breite = 12 Tiefe = 32 # Daraus können nach den bekannten Formeln # das Volumen und die Oberfläche berechnet werden. Volumen = Hoehe * Breite * Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) # Die berechneten Werte werden ausgegeben. print(Volumen) print(Oberflaeche) Das Programm rechnet mit ganzen Zahlen und benutzt die Operationen + und *. 1.2.2 Übersicht der grundlegenden Datentypen Typ Werte int ganze Zahlen 2016 -12 11267456 float Dezimalbrüche 3.14 2.5 6.022e+23 str Zeichenfolgen bool Wahrheitswerte int Beispiele für Literale 'AB' ` ´ ˚ {{ % ˚˚ ` ´ ˚ { ˚˚ 'Hello world' '2.5' True False `˚ and or not . . . integer float . . . floating-point number str Operatoren (Fließkommazahl) . . . string bool . . . boolean (George Boole, 1815-1864) 1.2.3 Begriffe Hoehe = 3 Breite = 4 Tiefe = 5 Volumen = Hoehe*Breite*Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) Das Programm besteht aus vier Anweisungen. Jede Anweisung hat die Form Variable = Ausdruck. 1.2.4 Begriffe Hoehe = 3 Breite = 4 Tiefe = 5 Volumen = Hoehe*Breite*Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) Das Programm besteht aus vier Anweisungen. Jede Anweisung hat die Form Variable = Ausdruck. Die Ausdrücke 3, 4, 5 und 2 sind Literale vom Typ int und erzeugen Objekte vom Typ int. 1.2.4 Begriffe Hoehe = 3 Breite = 4 Tiefe = 5 Volumen = Hoehe*Breite*Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) Das Programm besteht aus vier Anweisungen. Jede Anweisung hat die Form Variable = Ausdruck. Die Ausdrücke 3, 4, 5 und 2 sind Literale vom Typ int und erzeugen Objekte vom Typ int. Die Variablen Hoehe, Breite und Tiefe und Volumen werden an sie gebunden. 1.2.4 Begriffe Hoehe = 3 Breite = 4 Tiefe = 5 Volumen = Hoehe*Breite*Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) Das Programm besteht aus vier Anweisungen. Jede Anweisung hat die Form Variable = Ausdruck. Die Ausdrücke 3, 4, 5 und 2 sind Literale vom Typ int und erzeugen Objekte vom Typ int. Die Variablen Hoehe, Breite und Tiefe und Volumen werden an sie gebunden. Der Ausdruck Hoehe*Breite*Tiefe multipliziert Variablen, die an Objekte vom Typ int gebunden sind, und erzeugt deshalb ein Objekt vom Typ int. 1.2.4 Begriffe Hoehe = 3 Breite = 4 Tiefe = 5 Volumen = Hoehe*Breite*Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) Die Variablen Hoehe, Breite und Tiefe und Volumen werden an sie gebunden. Der Ausdruck Hoehe*Breite*Tiefe multipliziert Variablen, die an Objekte vom Typ int gebunden sind, und erzeugt deshalb ein Objekt vom Typ int. Der Ausdruck 2*(Hoehe*Breite+Hoehe*Tiefe+Breite*Tiefe) multipliziert und addiert int-Objekte und erzeugt deshalb ein Objekt vom Typ int. 1.2.4 Begriffe Hoehe = 3 Breite = 4 Tiefe = 5 Volumen = Hoehe*Breite*Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) Der Ausdruck Hoehe*Breite*Tiefe multipliziert Variablen, die an Objekte vom Typ int gebunden sind, und erzeugt deshalb ein Objekt vom Typ int. Der Ausdruck 2*(Hoehe*Breite+Hoehe*Tiefe+Breite*Tiefe) multipliziert und addiert int-Objekte und erzeugt deshalb ein Objekt vom Typ int. Am Ende ist Volumen an ein Objekt vom Typ int mit Wert 60 gebunden und Oberflaeche ist an ein Objekt vom Typ int mit Wert 94 gebunden. 1.2.4 Ausdrücke vom Typ int Operatoren + - * ** (Addition, Subtraktion, Multiplikation, Potenz) bestehen aus § Literalen vom Typ int § Variablen, die an Objekte vom Typ int gebunden sind § den Operatoren + - * ** // % § ... + - * ** stehen für Addition, Subtraktion, Multiplikation und Potenz. Beispiele für int-Literale: 2017 0 -7592 2154816 Beispiele für int-Ausdrücke aus Literalen: 60 * 60 * 24 (52-6)*40 -7592*2154816 (5+7)**2 5**2 + 2*5*7 + 7**2 Operator // (ganzzahlige Division) a // b ist der ganzzahlige Anteil bei der Division von a durch b. 17 // 6 ist 2 (da 17 “ 2 ¨ 6 ` 5), und -17 // 6 ist -3 (da ´17 “ ´3 ¨ 6 ` 1). Beispiele für int-Ausdrücke aus Literalen: (49*48*47*46*45*44)//(1*2*3*4*5*6) 80000000//(365*24) ((17*60+25)-(16*60+15))//60 Mathematische Schreibweise für die ganzzahlige Division: a // b entspricht t ba u tx u ist die größte ganze Zahl ď x ( untere Gaußklammer“) ” 1.2.6 Operator % (modulo-Operation) a % b ist der Rest bei der ganzzahligen Division von a durch b. 17 % 6 ist 5 (da 17 “ 2 ¨ 6 ` 5), und -17 % 6 ist 1 (da ´17 “ ´3 ¨ 6 ` 1). Mathematische Schreibweise für a % b ist a mod b . Beispiele für int-Ausdrücke aus Literalen: ((17*60+25)-(16*60+15))%60 ((17*60+25)-(16*60+15))//60 Die Operatoren haben unterschiedliche Bindungsstärke (entsprechend Punktrechnung geht vor Strichrechnung“). ” Im Zweifel: Klammern setzen . . . 1.2.7 Weitere Beispiele für int-Ausdrücke (mit int-Variablen (farbig notiert)): hh * 60 * 60 + mm * 60 + sec (52 - 6) * 40 // LP_pro_Jahr (1+5*((jahr-1)%4)+4*((jahr-1)%100)+6*((jahr-1)%400))%7 Anweisungen Eine Anweisung besteht aus einer Variablen, = und einem Ausdruck. jahr = 2017 w = (1+5*((jahr-1)%4)+4*((jahr-1)%100)+6*((jahr-1)%400))%7 Arbeitsstunden_pro_LP = (52 - 6) * 40 // LP_pro_Jahr zaehler = zaehler + 1 Beim Abarbeiten einer Anweisung an eine Variable eines grundlegenden Datentyps wird § zuerst der Ausdruck ausgewertet und ein Objekt mit Typ und Wert des Ausdrucks erzeugt, § danach wird die Variable an das Objekt gebunden. #----------------------------------------------------------------# oberflaeche.py #----------------------------------------------------------------# Berechne das Volumen und die Oberfläche eines Quaders. # Zuerst werden die Maße des Quaders angegeben. Hoehe = 5 Breite = 12 Tiefe = 32 # Daraus können nach den bekannten Formeln # das Volumen und die Oberfläche berechnet werden. Volumen = Hoehe * Breite * Tiefe Oberflaeche = 2 * ( Hoehe*Breite + Hoehe*Tiefe + Breite*Tiefe ) # Die berechneten Werte werden ausgegeben. print(Volumen) print(Oberflaeche) #----------------------------------------------------------------# python oberflaeche.py # 1920 # 1208 Ausdrücke vom Typ str Operatoren + * . . . dienen dem Verarbeiten von Texten. Die Literale vom Typ str sind Folgen von Zeichen, die durch ' ... ' oder " ... " eingeschlossen sind. 'Das folgende ist kein int-Literal.' '1234' Die Operation + schreibt Strings hintereinander (Konkatenation). 'Das ist ' + 'ein Satz.' ergibt 'Das ist ein Satz.' . Die Operation * ist eine Operation zwischen str und int. 'Ole'*4 ergibt 'OleOleOleOle'. 1.2.11 #-------------------------------------------------------------------------# zollstock.py #-------------------------------------------------------------------------# Gib (auf standard output) die Längen der Striche aus, # die im Millimeter-Abstand auf einem Zollstock sind. # Die Striche für die Millimeter haben Länge 1, # der Strich bei 5mm hat Länge 2, # der Strich bei 1cm hat Länge 3, bei 5cm Länge 4, etc. vier_Millimeter = '1111' neun_Millimeter = vier_Millimeter + '2' + vier_Millimeter fuenf_Zentimeter = (neun_Millimeter + '3')*4 + neun_Millimeter + '4' print(vier_Millimeter) print(neun_Millimeter) print(fuenf_Zentimeter) #----------------------------------------------------------------------# python zollstock.py # 1111 # 111121111 # 11112111131111211113111121111311112111131111211114 int-Werte zu str-Werten umwandeln Die Funktion str( ) macht aus einem Objekt einen String. Z.B. liefert str(123) den String '123'. #--------------------------------------------------------------------------# teilen_v1.py #--------------------------------------------------------------------------# Gib das Ergebnis der ganzzahligen Division von a durch b und den Rest aus. #--------------------------------------------------------------------------import stdio a = 213 b = 15 stdio.write( str(a) + ' geteilt durch ' + str(b) + ' ergibt ' ) stdio.writeln( str( a//b ) + ' Rest ' + str( a%b ) + '.' ) #---------------------------------------------------------------------------# # python teilen_v1.py # 213 geteilt durch 15 ergibt 14 Rest 3. # 1.2.13 Eingaben von der Kommandozeile lesen Beim Starten eines Programms können Argumente an das Programm übergeben werden – sie sind stets vom Typ str. #------------------------------------------------------------------------# einundausgabe.py #------------------------------------------------------------------------# Lies drei (durch Leerzeichen getrennte) Strings aus der Kommandozeile # und gib sie in umgekehrter Reihenfolge wieder aus (auf standard output). #------------------------------------------------------------------------import sys a = sys.argv[1] b = sys.argv[2] c = sys.argv[3] print( c + ' ' + b + ' ' + a ) #-------------------------------------------------------------------------# python einundausgabe.py Hallo Martin . # . Martin Hallo # # python einundausgabe.py Hallo Martin. # Traceback (most recent call last): # File "einundausgabe.py", line 12, in <module> # c = sys.argv[3] # IndexError: list index out of range 1.2.14 str-Werte zu int-Werten umwandeln Entsprechend str( ) macht die Funktion int( ) aus einem Objekt ein int-Objekt. Z.B. liefert int('123') ein int-Objekt mit Wert 123. #--------------------------------------------------------------------------# teilen_v2.py: # Lies zwei int-Werte a und b von der Kommandozeile. # Gib das Ergebnis der ganzzahligen Division von a durch b und den Rest aus. #--------------------------------------------------------------------------import sys, stdio a = int( sys.argv[1] ) b = int( sys.argv[2] ) stdio.write( str(a) + ' geteilt durch ' + str(b) + ' ergibt ' ) stdio.writeln( str( a//b ) + ' Rest ' + str( a%b ) + '.' ) #--------------------------------------------------------------------------# python teilen_v2.py 1234 23 # 1234 geteilt durch 23 ergibt 53 Rest 15. # # python teilen_v2.py 1234 0 # File "teilen_v2.py", line 13, in <module> # stdio.writeln( str( a//b ) + ' Rest ' + str( a%b ) + '.' ) # ZeroDivisionError: integer division or modulo by zero 1.2.15 Ausdrücke vom Typ float Operationen + - * / ** . . . dienen dem Rechnen mit Dezimalbrüchen. Literale sind z.B. 4.0 123.45 3.141e+12 (steht für 3,141 ¨ 1012 ) Die Operationen mit float sind + - * / ** . Kommt in einem Ausdruck mit ints ein float-Wert vor, dann hat das Ergebnis Typ float (und nicht Typ int). float-Werte haben nur beschränkte Genauigkeit. stdio.writeln(str(1.234567890123456789e+18)) hat Ausgabe 1.2345678901234568e+18 1.2.16 Die quadratische Gleichung a ¨ x 2 ` b ¨ x ` c “ 0 hat die Lösungen x1,2 “ ´b ˘ ? b2 ´ 4 ¨ a ¨ c . 2¨a #---------------------------------------------------------------------------# mitternacht.py # Liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus. #---------------------------------------------------------------------------import stdio import sys import math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) diskriminante = math.sqrt(b**2 - 4 * a * c) stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #---------------------------------------------------------------------------# python mitternacht.py 4 -20.3 3.141 # 4.915241838383638 # 0.15975816161636258 1.2.17 #---------------------------------------------------------------------------# mitternacht.py # Liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus. #---------------------------------------------------------------------------import stdio import sys import math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) diskriminante = math.sqrt(b**2 - 4 * a * c) stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-----------------------------------------------------------------------------------# python mitternacht.py 4 6 2 # -0.5 # -1.0 # # # # # python mitternacht.py 1 2 3 Traceback (most recent call last): File "mitternacht.py", line 17, in <module> diskriminante = math.sqrt(b**2 - 4 * a * c) ValueError: math domain error float-Werte können ungenau sein #----------------------------------------------------------------------# fehler_mit_float.py #----------------------------------------------------------------------import stdio # 10^16 +1 wird als int-Literal dargestellt, # und 10^16 +1 wird als float-Wert dargestellt. int_zahl = 10**16 +1 float_zahl = 10.0**16 +1 # Beide Zahlen werden ausgegeben. stdio.writeln('int Zahl: ' + str(int_zahl)) stdio.writeln('float Zahl: ' + str(float_zahl)) stdio.writeln('float Zahl als int: ' + str(int(float_zahl))) #----------------------------------------------------------------------# python fehler_mit_float.py # int Zahl: 10000000000000001 # float Zahl: 1e+16 # float Zahl als int: 10000000000000000 1.2.19 Bemerkungen zu Funktionen Eingebaute“ Funktionen: ” str( ), int( ), float( ), bool( ), abs( ) (der Betrag einer Zahl), round( ) (nächster int-Wert), max( , ), min( , ) (Maximum bzw. Minimum zweier Zahlen) . . . Standard-Funktionen aus Standard-Modulen von Python: math.sqrt( ), math.log( , ), random.random() (eine zufällige float-Zahl x mit 0 ď x ă 1), random.randrange(x,y) (eine zufällige int-Zahl aus rx, y q), . . . Funktionen aus den Modulen für das Buch: stdio.write( ), stdio.writeln( ), . . . 1.2.20 Ausdrücke vom Typ bool Operationen and or not * . . . dienen dem Rechnen mit Wahrheitswerten True und False. Es gibt die Operation and, or und not auf bool-Objekten: a b False False False True True False True True a and b False False False True a or b False True True True a False True not a True False Die Operation * ist zwischen str-Objekten und bool-Objekten: 'Ein String'*True ergibt 'Ein String', und 'Ein String'*False ergibt ''. 1.2.21 Operation * ist zwischen beliebigen Objekten und bool-Objekten: a * True ergibt a (meistens), und a * False ergibt einen Nullwert. Beispiele: 17 * True ergibt 17 17 * False ergibt 0 'Wahr' * True ergibt 'Wahr' 'Wahr' * False ergibt '' True * True ergibt 1 True * False ergibt 0 1.2.22 Vergleichsoperationen liefern bool-Werte Operator == != < <= > >= Bedeutung Beispiel True False gleich 3==3 2==3 ungleich 2!=3 3!=3 kleiner als 2<3 3<3 kleiner oder gleich 3<=3 4<=3 größer als 4>3 3>4 größer oder gleich 4>=3 3>=4 1.2.23 #-----------------------------------------------------------------------------------# schaltjahr.py #-----------------------------------------------------------------------------------# Lies int-Wert jahr als Argument von der Kommandozeile. # Gib aus, ob jahr ein Schaltjahr ist. import stdio import sys jahr = int(sys.argv[1]) istSchaltjahr = (jahr % 4 == 0) # Ein Schaltjahr ist durch 4 teilbar istSchaltjahr = istSchaltjahr and (jahr % 100 != 0) # und nicht durch 100 teilbar istSchaltjahr = istSchaltjahr or (jahr % 400 == 0) # oder durch 400 teilbar. stdio.writeln(str(jahr) + ' ist ' + 'k'*(not istSchaltjahr) + 'ein Schaltjahr.') #-------------------------------------------------------------------------------------# python schaltjahr.py 2016 # 2016 ist ein Schaltjahr. # python schaltjahr.py 1900 # 1900 ist kein Schaltjahr. # python schaltjahr.py 2000 # 2000 ist ein Schaltjahr. 1.2.24 #----------------------------------------------------------------------# tippspiel.py # Lies ein int zahl von Spieler 1 von der Kommandozeile # und würfele anschließend eine weitere Zahl (wurf) von Spieler 2. # Spieler 1 hat gewonnen, falls beide Spieler eine ungerade Zahl haben # oder beide Spieler eine gerade Zahl haben. #----------------------------------------------------------------------import stdio import sys import random zahl = int(sys.argv[1]) wurf = random.randrange(1,7) stdio.write('Spieler 1 hat ' + str(zahl) + ' gewählt und ') stdio.writeln('Spieler 2 hat ' + str(wurf) + ' gewürfelt.') ergebnis = ( (zahl % 2) == (wurf % 2) ) stdio.writeln('Spieler 1 gewinnt' + ' nicht'*(not ergebnis) + '.') #-------------------------------------------------------------------------# python tippspiel.py 3 # Spieler 1 hat 3 gewählt und Spieler 2 hat 5 gewürfelt. # Spieler 1 gewinnt. # # python tippspiel.py 3 # Spieler 1 hat 3 gewählt und Spieler 2 hat 2 gewürfelt. # Spieler 1 gewinnt nicht. 1.2.25 Zusammenfassung § Wir haben die elementaren Daten-Typen int, float, str und bool von Python kennengelernt. § Wir können Ausdrücke aus Literalen, Variablen, Operatoren und Funktionen schreiben. § Wir können sehr einfache Programme mit Eingabe von Argumenten Abarbeitung einer festen Folge von Anweisungen Ausgabe von Ergebnissen schreiben und deren Ausführung nachvollziehen. 1.2.26