Martin Teufel Matr.-Nr.: 3136289 Tutorin: Eva Reitz (G3; besuche G4) PRG-1 – Übung 05 Aufgabe 1 – Aggregierte Datentypen & Klassen a) Queue # -*- coding: cp1252 -*# Queue-/Warteschlangen-Implemetierung in Python (FIFO) class CQueue(object): __Liste__=[] def enqueue(self, einf_Objekt): CQueue.__Liste__.insert(0,einf_Objekt) print "aktuelle Queue:" print CQueue.__Liste__ print def dequeue(self): if len(CQueue.__Liste__)==0: print "None" print return None else: x=CQueue.__Liste__[len(CQueue.__Liste__)-1] print "entfernt: ",x del CQueue.__Liste__[len(CQueue.__Liste__)-1] print "aktuelle Queue:" if len(CQueue.__Liste__)!=0: print CQueue.__Liste__ print else: print "None" print Queue=CQueue() term=False print "Queue-Implementierung" print "---------------------" print while term==False: print "Was möchten Sie tun?" was_tun=raw_input ("Ein Objekt hinzunfügen (h), das Vorderste entfernen (e) oder beenden (b)?: ") if was_tun == "h": einf_Objekt=raw_input ("Bitte das einzufügenden Objekt eingeben: ") try: einf_Objekt=int(einf_Objekt) except ValueError: pass Queue.enqueue(einf_Objekt) elif was_tun == "e": Queue.dequeue() elif was_tun == "b": print print "Programm beendet." term=True else: print "Falsche Eingabe!" -1- b) Stack # -*- coding: cp1252 -*# Stack-Implemetierung in Python (LIFO; links entspricht unten, rechts entspricht oben) import operator; class CStack(object): __Liste__=[] def push(self, einf_Objekt): Stack.__Liste__.append(einf_Objekt) print "aktueller Stack:" print CStack.__Liste__ print def pop(self): if len(Stack.__Liste__)==0: print "None" print return None else: x=CStack.__Liste__[len(CStack.__Liste__)-1] print "entfernt: ",x del CStack.__Liste__[len(CStack.__Liste__)-1] print "aktueller Stack:" if len(CStack.__Liste__)!=0: print CStack.__Liste__ print else: print "None" print Stack=CStack() term=False print "Stack-Implementierung" print "---------------------" print while term==False: print "Was möchten Sie tun?" was_tun=raw_input ("Ein Objekt hinzunfügen (h), das Oberste entfernen (e) oder beenden (b)?: ") if was_tun == "h": einf_Objekt=raw_input ("Bitte das hinzuzufügenden Objekt eingeben: ") try: einf_Objekt=int(einf_Objekt) except ValueError: pass Stack.push(einf_Objekt) elif was_tun == "e": Stack.pop() elif was_tun == "b": print print "Programm beendet." term=True else: print "Falsche Eingabe!" -2- Aufgabe 2 – Parameter und Objektmanagement a) call by value / call by reference Unter “call by value” beim Aufruf einer Prozedur oder Funktion versteht man die Übergabe des Wertes einer Variable, d.h. hierbei wird eine Kopie des Wertes der Prozedur- oder Funktionsvariable zugewiesen. Anders bei „call by reference“: Hier wird nur die Speicheradresse übergeben, d.h. Prozedur- oder Funktionsvariable verweist lediglich auf die Ausgangsvariable (=Referenz). Dadurch wird (evtl. unnötig belegter) Speicherplatz eingespart. Aus diesem Unterschied folgt aber auch: Wird in der Prozedur oder Funktion der Wert geändert, ändert sich dieser bei „call by reference“ auch in der Ausgangsvariable, bei „call by value“ hingegen nicht, da ja nur die Kopie geändert wird. b) Kopieren von Objekten Es gibt zwei Möglichkeiten, Objekte zu kopieren: Prinzipiell kopiert man Objekte mit Hilfe des Moduls „copy“, bzw. dessen Methoden, deren es wie schon erwähnt Zwei an der Zahl gibt. Das sieht dann z.B. wie folgt aus: import copy [...] p2 = copy.copy(p1) Dieses normale oder „flache“ Kopieren funktioniert (wie ersichtlich ist) mit der gleichnamigen Methode „copy“ (copy.copy(Objekt)). Dadurch wird nur das Objekt selber kopiert, und nichts weiter. Des weiteren gibt es aber noch das „tiefe“ Kopieren (deepcopy). Diese Methode kopiert nicht nur das Objekt selbst, sondern auch noch alle „darunter liegenden“/eingebetteten Objekte, so daß das Objekt vollständig, also quasi mit allem, was dazu gehört kopiert wird (vergleiche del und deltree bei MS-DOS). Das ganze sieht dann z.B. so aus: import copy [...] p2 = copy.deepcopy(p1) Ein Unterschied ist z.B. auch der, daß bei Änderungen an einem eingebetteten Objekt beim „flachen Kopieren“ sich die Änderungen auf beide „Elterobjekte“ auswirken, beim „tiefen Kopieren“ eben nicht, da dabei beides völlig voneinander getrennte Objekte sind. Aufgabe 3 – Rekursion a) Testprogramm zur Rekursionstiefe Nach der erreichen des Rekursionslimits resp. der maximalen Rekursionstiefe (standardmäßig 1000) bricht der Interpreter die Ausführung des Algorithmus’ ab (bei mir komischerweise schon bei 979 bzw. immer exakt 21 Rekursionen früher) und gibt nur noch Fehlermeldungen aus, bis schließlich (zumindest bei mir) der gesamte Prozeß terminiert. Die Festlegung der maximalen Rekursionstiefe beugt unendlicher Rekursion vor, und hilft einen Stack-Überlauf zu verhindern, was zum Absturz von Python führen könnte/würde (was bei mir seltsamer Weise aber trotzdem aufgrund der anhaltenden Ausgabe von Fehlermeldungen geschieht). b) Rekursionstiefe festlegen Mit dem Befehl bzw. der sys-Methode „setrecursionlimit“ kann man durch sys.setrecursionlimit(Limit) die maximale Rekursionstiefe festlegen, was wie bereits beschreiben einen Stack-Überlauf verhindert bzw. verhindern soll. Das höchstmögliche Limit ist dabei Plattform-abhängig. → siehe hierzu auch mein selbstgeschriebenes Testprogramm „Rekursionslimit festlegen und ausgeben“ c) & d) → siehe Abgabe von Susanne Lipp (G4) -3- Rekursionsbaum zu d) -4-