Algorithmen und Programmierung 2, SS 2016 — 1. ¨Ubungsblatt

Werbung
Algorithmen und Programmierung 2, SS 2016 — 1. Übungsblatt
Aufgaben zum Vorkurs, ohne Abgabe und ohne Bewertung.
Teil A, für Studierende ohne Programmiererfahrung
1. Kalenderrechnungen
(a) Schreiben Sie eine Funktion, die für ein Datum (Jahr, Monat, Tag) im gregorianischen Kalender die Anzahl der Tage berechnet, die seit dem 1901–01–01
vergangen sind. Für 1900–12–31 sollte das Ergebnis also −1 sein.
(b) Schreiben Sie eine Funktion zur Bestimmung des Wochentags für ein gegebenes
Datum.
(c) Schreiben Sie eine Funktion, die berechnet, wie oft der 13. seit dem 1700–01–01
bis heute auf einen Samstag, Sontag, Montag, Dienstag, . . . oder Freitag gefallen
ist.
(d) Die Länge des tropischen Jahres (also des mittleren astronomischen Sonnenjahres, das die Jahreszeiten bestimmt) beträgt etwa 365,242 19 Tage. Der gregorianische Kalender hat eine Periode von 400 Jahren. Welche mittlere Länge hat
das gregorianische Kalenderjahr? Wann wird sich die Abweichung zwischen dem
gregorianischen Kalender und der tropischen Jahreslänge so weit aufsummiert
haben, dass man den Kalender um einen ganzen Tag korrigieren müsste, um die
Abweichung auszugleichen? Muss man dann einen Extraschalttag einschieben,
oder muss man einen Schalttag ausfallen lassen?
2. Schleifen, Textbilder
Schreiben Sie ein Programm, das folgende Pyramide zunächst als Liste von Zeilen
erzeugt und dann ausgibt.
1
121
12321
1234321
123454321
12345654321
1234567654321
3. Summen
Berechnen Sie mit Gleitkommaarithmetik die Summen
100
10000
X
1 X 1
,
,
n
n
n=1
n=1
1000000
X
n=1
100
10000
1 X 1 X 1
,
,
,
n
n2
n2
n=1
n=1
1000000
X
n=1
1000
20
X 1
1 X 1
,
,
und
.
2
n
n!
n!
n=1
n=1
4. Priorität einstelliger und zweistelliger Operatoren
Was ist das Ergebnis der folgenden Rechnungen?
a=10; -a//3, 0-a//3, a//-3, 0-a//3,
-a%3, 0-a%3, a%-3, 0-a%3
Versuchen Sie, die Antwort vorherzusagen, und probieren Sie es dann aus. Gilt in
jedem Fall die Formel (a//b)*b + a%b = a?
1
5. Funktionen
Schreiben Sie Funktionen, die als Argument eine Liste von Zeilen erhalten und das
dargestellte Bild (wie in Aufgabe 2)
(a) vertikal spiegeln (unten und oben vertauschen),
(b) horizontal spiegeln (links und rechts vertauschen),
(c) um 90◦ nach links drehen.
Die einzelnen Zeilen sollen kein Zeilenendezeichen "\n" enthalten, und sie dürfen
verschieden lang sein.
6. Grafik, Vektorrechnung
Das nebenstehende Bild zeigt einen Ausschnitt aus
dem Bild Fibonacci meets Pythagoras“ von Eugen
”
Jost1 , das aus Quadraten besteht. (Insbesondere die
kleineren Quadrate sind jedoch nicht sehr genau gezeichnet.) Gleich große Quadrate haben dieselbe Farbe. Schreiben Sie eine Funktion, die mit dem turtlePaket die ersten n Quadrate dieser Spirale zeichnet.
(Bei Jost sind es n = 25 Quadrate.)
Zusatzaufgabe: Das Bild soll eine vorgegebene Rechtecksfläche mit den Ausmaßen L × B möglichst gut
ausfüllen und in dieser Fläche zentriert sein.
7. Schleifenabbruch
Das folgende Programm soll alle Dateien im aktuellen Dateiordner auflisten, deren
Name mit .txt aufhört, und in denen vor dem Vorkommen des ersten Symbols !“
”
jede Zeile das Symbol +“ enthält.
”
import os
for Name in os.listdir():
if Name.endswith(".txt"):
Datei = open(Name, encoding=’utf-8’, errors=’ignore’)
for Zeile in Datei:
for Zeichen in Zeile:
if Zeichen == "+":
break
if Zeichen == "!":
continue
else:
continue
else:
print (Name)
Datei.close()
Welche Dateien werden von diesem Programm tatsächlich ausgegeben? Stellen Sie
das Programm richtig.
1
Aus dem Mathematikkalender Alles ist Zahl“, April 2010, siehe http://mathematik-und-kunst.de/
”
2
8. Unveränderliche und veränderliche Datenstrukturen
Was wird von der folgenden Befehlsfolge ausgegeben? Welche Befehle sind ungültig?
a=[1,3,(4,2)]
b=(a,a,[1,5,4,3])
print(b[1][2])
b[1][2]="wer"
print(b)
a[2][1]
a[2][1]="wann"
print(b)
b[2][1]
b[2][1]=["wo","wie"]
print(b)
b[2]=[2,4]
print(b)
a="warum"
print(b)
Teil B, für Studierende mit Programmiererfahrung
9. Sitzplatzzuteilung bei einer Klausur.
Bei einer Klausur sollen n Prüflinge in einen oder mehrere Hörsäle gepfercht werden, sodass
möglichst viele Teilnehmerinnen einen möglichst großen Mindestabstand voneinander ha”
ben.“ Im Netz finden Sie, wie eine Lösung als PDF-Datei2 oder als Textgraphik3 ausschauen
könnte.
Erstellen Sie eine kleine Anwendung in Python, die diese Aufgabe unterstützt. Dabei
müssen Sie einige Aspekte der Aufgabe selbst noch genauer spezifizieren. Hier sind verschiedene Teilaufgaben, die Sie auch unabhängig voneinander oder gemeinsam mit anderen
Teams in Angriff nehmen können.
(a) Überlegen Sie sich ein geeignetes Eingabeformat für Hörsäle.
(b) Schreiben Sie ein Programm zur Ausgabe einer Lösung
(i) grafisch, zur Übersicht4 , und
(ii) in Listenform, damit die Prüflinge ihre Plätze finden können.
(c) Formulieren Sie Kriterien, nach denen man verschiedene vorgeschlagene Lösungen vergleichen kann. Zum Beispiel sollte es in der ersten Lösung2 besser bewertet werden,
wenn die freien Plätze links und rechts von #19 und #28 gleichmäßiger aufgeteilt
werden.
(d) Schreiben Sie ein Programm, das zwei vorgeschlagene Lösungen anhand dieser Kriterien
miteinander vergleicht, zum Beispiel, indem es für jede Lösung eine Maßzahl für die
Güte berechnet.
(e) Versuchen Sie, einen möglichst guten Sitzplan zu erstellen.
2
http://www.inf.fu-berlin.de/lehre/WS15/ALP3/Hoersaal2.pdf
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/hoersaalraster.txt
4
Eine einfache Möglichkeit zur Erstellung einer graphischen Ausgabe bietet das Python-Paket turtle.
Das erstellte Bild kann dann zum Beispiel als Bildschirmfoto aufgenommen werden oder mit dem Befehl
Screen().getcanvas().postscript(file=’Ausgabe.eps’) in eine PostScript-Datei umgewandelt werden.
3
3
Algorithmen und Programmierung 2, SS 2016 — 2. Übungsblatt
Abgabe bis Freitag, 29. April 2016, 12:00 Uhr,
Hinweise zu den Programmieraufgaben in Python: Geben Sie Ihrem Programm für
Aufgabe N den Namen AufgabeN _Nachname1 _Nachname2 .py. Beim Auruf dieses Programms aus der Kommandozeile soll eine Testsuite ablaufen, in der jede Funktion mindestens einmal aufgerufen wird. Sie dürfen Unterprogramme in getrennte Module packen, aber
die Modulnamen müssen in der gleichen Weise mit Ihren Nachnamen gekennzeichnet sein.
Laden Sie die Programme elektronisch im KVV hoch, und geben Sie zusätzlich die ausgedruckten Programme zusammen mit den anderen Lösungsbestandteilen in Papierform in
die Fächer der Tutoren ab.
1) Verwenden Sie sprechende Namen für Variablen und Funktionen, die den Inhalt
der Variablen oder die Funktionalität der Funktion charakterisieren.
2) Verwenden Sie die vorgegebenen Funktionsnamen, falls diese angegeben sind.
3) Kommentieren Sie das Programm.
4) Verwenden Sie geeignete Hilfsvariablen und Hilfsfunktionen.
5) Löschen Sie Programmzeilen und Variablen, die nicht verwendet werden.
10. Wörterbücher und Mengen, Sammelbilder, 0 Punkte
(a) Untersuchen Sie experimentell, wie oft man eine zufällige Zahl zwischen 1 und n
wählen muss, bis jede Zahl vorgekommen ist. Machen Sie für n = 10, 100, und
1000 jeweils 100 Experimente, und bestimmen Sie für jedes n das Minimum,
das Maximum, und den Mittelwert der Anzahl der Zahlen. Ein Experiment
besteht dabei aus der notwendigen Anzahl von Versuchen, bis man alle Zahlen
beobachtet hat. (Zufällige ganze Zahlen kann man mit der Bibliotheksfunktion
random.randint erzeugen. Der Erwartungswert für die Anzahl der Versuche ist
übrigens n(1 + 21 + 13 + · · · + n1 ).)
(b) Bestimmen Sie bei jedem Experiment auch, wie oft die häufigste Zahl vorgekommen ist, und machen Sie eine analoge Statistik wie bei Aufgabe (a).
11. Boolesche Ausdrücke, 0 Punkte
Schreiben Sie die Funktion schaltjahr1 zum Testen, ob ein Jahr ein Schaltjahr ist,
möglichst knapp mit einem einzigen Booleschen Ausdruck und ohne if-Anweisungen.
(Ist diese Fassung leichter zu verstehen als das ursprüngliche Programm?)
12. Der erweiterte Euklidische Algorithmus, 15 Punkte
(a) Schreiben Sie ein Python-Programm testGGT, das die Ausgabe t, r, s des erweiterten Euklidischen Algorithmus überprüft, ob sie eine gültige Ausgabe zur
Eingabe a, b ist (und ob t somit der größte gemeinsame Teiler von a und b ist).
(b) Der größte gemeinsame Teiler t von a und b hat die Eigenschaften:
i. t teilt a, und t teilt b, (d.h. t ist ein gemeinsamer Teiler von a und b).
ii. Jeder gemeinsame Teiler d von a und b teilt auch t.
Ist die ganze Zahl t für die Eingabe a = 7 und b = 11 durch diese beiden
Bedingungen eindeutig charakterisiert?
(c) Wenn man die beiden obigen Bedingungen als Richtschnur nimmt, was müsste
dann ggT(a, 0) sein? Was müsste ggT(0, 0) sein?
1
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/schaltjahr.py
4
(d) Schreiben Sie eine Python-Funktion zur Berechnung von ggT(a, b) für beliebige
ganze Zahlen a, b. mit dem erweiterten Euklidischen Algorithmus. Das Ergebnis
t soll ≥ 0 sein. (Natürlich dürfen Sie nicht einfach eine Bibliotheksfunktion zu
Hilfe nehmen.) Aufruf: t,r,s = ggT(a,b).
13. Turm von Hanoi, 15 Punkte
Ergänzen Sie folgendes rekursive Programm2 zur Lösung des Hanoi-Problems:
def Hanoi(n, Start, Hilfsstift, Ziel):
"""Turm von Hanoi
Bewege n Scheiben, die zu Beginn auf dem Stift "Start" sind,
zum Stift "Ziel"; "Hilfsstift" ist der dritte Stift."""
if n==0: return
Hanoi(n-1, Start, Ziel, Hilfsstift)
setze_um(n, Start, Ziel)
Hanoi(n-1, Hilfsstift, Start, Ziel)
(a) Verwalten Sie die Scheiben auf den Stiften, indem Sie geeignete Datenstrukturen verwenden. Diese Struktur soll eine globale Variable mit dem Namen
Stifte sein. insbesondere soll die Prozedur setze_um(n, x, y) die Scheibe n
von Stift x auf Stift y umsetzen, und dabei soll überprüft werden, ob die Regeln
eingehalten werden.3 Andernfalls soll das Programm eine Fehlermeldung ausgeben und mit der Anweisung raise RuntimeError eine Ausnahme erzeugen.
(b) Die Initialisierung init_Hanoi(n, x, y, z) soll die drei Stifte erzeugen und
n Scheiben auf den ersten Stift setzen. Die Benennung x, y, z der Scheiben soll
dabei frei wählbar sein. Ein Beispiel eines Initialisierungsaufrufs wäre:
init_Hanoi(10, ’A’, ’B’, ’C’)
(c) Eine Funktion anzeigen() soll den Zustand der Stifte anzeigen.
(d) Eine Boolesche Funktion fertig() soll überprüfen, ob das Ziel erreicht ist.
14. Iterative Lösung des Hanoi-Problems, 0 Punkte
Beweisen Sie:
(a) Wenn n gerade ist und die Lösung mit dem Aufruf Hanoi(n, ’A’, ’B’, ’C’)
gestartet wird, dann bewegen sich die Scheiben mit geraden Nummern immer
nur zyklisch in “aufsteigender” Richtung A → B → C → A, und die Scheiben
mit ungeraden Nummern in der umgekehrten Richtung.
(b) Es wird immer abwechselnd Scheibe 1 und eine andere Scheibe bewegt.
(c) In jeder möglichen Konfiguration gibt es höchstens drei Züge, die den Regeln
entsprechen.
Mit Hilfe dieser Beobachtungen kann man die Folge der Bewegungen mit einem Programm bestimmen, das ohne Rekursion auskommt.
15. Langsamste Lösung des Hanoi-Problems, 0 Punkte, zum Tüfteln
Lösen Sie das Problem, die Scheiben von Stift A auf Stift C zu bringen, indem Sie
möglichst viele Schritte machen, ohne dass sich jedoch eine Konfiguration wiederholt.
Können Sie alle möglichen Konfigurationen durchlaufen? Ist die Lösung eindeutig?
2
Siehe http://www.inf.fu-berlin.de/lehre/SS16/ALP2/Hanoi.py
Es darf immer nur die oberste Scheibe auf einem Stift bewegt werden, und sie darf nicht auf einer
kleineren Scheibe landen.
3
5
Algorithmen und Programmierung 2, SS 2016 — 3. Übungsblatt
Abgabe bis Freitag, 6. Mai 2016, 12:00 Uhr. Aufgabe 18b korrigiert
16. Transposition einer Matrix, 10 Punkte
(a) Wir können eine (m × n)-Matrix (mit m, n ≥ 0) in Python zeilenweise“ als
”
eine Liste
von m Listen der Länge n darstellen, also zum Beispiel die Matrix
1 2 5
A =
als A=[[1,2,5],[4,3,7]]. Die Funktion transpose soll die
4 3 7
transponierte (n × m)-Matrix AT bestimmen, bei der Zeilen mit Spalten vertauscht sind. Schreiben Sie die Vor- und Nachbedingung der Zuweisung
B = transpose(A)
so, dass die Funktion transpose dadurch möglichst genau spezifiziert wird.
Denken Sie auch an die Prüfung, ob A eine gültige Eingabe ist:
type(A) = list ∧ (∀z ∈ A : type(z) = list) ∧ . . .
(b) (0 Punkte, freiwillig) Implementieren Sie die Funktion transpose in Python.
17. Ägyptische Multiplikation, 10 Punkte
Die nebenstehende Funktion multipliziert zwei nichtnegative
ganze Zahlen.
def mul(a0,b0):
a,b = a0,b0
s = 0
while a!=0:
if a%2==1:
s = s+b
a = a//2
b = b*2
return s
(a) (0 Punkte) Führen Sie den Algorithmus mit einigen speziellen und allgemeinen Beispielen per Hand (oder mit
Computerunterstützung) durch, bis Sie ihn verstehen.
(b) Finden Sie eine möglichst aussagekräftige Schleifeninvariante, aus der die Korrektheit des Algorithmus ersichtlich
ist. Sie können sich dabei auf die Ausgangswerte a0 , b0 der Parameter beziehen.
(c) (Programmieraufgabe, im KVV hochzuladen) Fügen Sie Ihre Invariante als
assert-Zusicherung am Schleifenanfang ein, und testen Sie sie.
(d) Funktioniert das Verfahren auch, wenn a < 0 ist? Was passiert, wenn a nicht
ganzzahlig ist? Wie ist es bei b? Begründen Sie Ihre Antworten.
18. Hoare-Kalkül, 10 Punkte
Beweisen Sie folgende Aussagen, oder finden Sie Belegungen der Variablen, sodass
die Vorbedingungen erfüllt sind, aber nach der Ausführung des Programms nicht die
Nachbedingungen. Geben Sie bei den Beweisen alle benützten Regeln an.
(a)
(c)
(d)
(e)
(f)
{ } a=x; b=y; b=b+a { b = x + y }
(b) { } u=a-5/2; v=u*2-1/2 { v ≥ 0 }
{ x = as + r } a=a+1; r=r-s { x = as + r }
{ a ∈ Z } x=a-5/2; z=x**2-1/4 { z ≥ 0 }
{ 0 ≤ x < t } t=t//2; x=x-t { x ≤ t }
(0 Punkte) { a = x ∧ b = y } a-=b; b+=a; a-=b { a = −y ∧ b = x }
19. (0 Punkte) Schreiben Sie eine Funktion is_sorted(L), die für eine Liste L kontrolliert, ob die Elemente der Liste sortiert sind. Das Ergebnis ist ein Paar (Auf,Ab).
Auf = 1, wenn die Liste aufsteigend sortiert ist, aber Auf = 2, wenn sie sogar streng
aufsteigend sortiert ist, das heißt, wenn alle Elemente verschieden sind; sonst ist
Auf = 0. Ab ist das analoge Ergebnis für absteigende Sortierung. (Kann eine Liste
überhaupt sowohl aufsteigend als auch absteigend sortiert sein?)
6
Algorithmen und Programmierung 2, SS 2016 — 4. Übungsblatt
Abgabe bis Freitag, 13. Mai 2016, 12:00 Uhr
20. Elimination von continue, 8 Punkte
Schreiben Sie zu den beiden folgenden Beispielen äquivalente Programme ohne die
Anweisungen break und continue und ohne die else-Klausel bei der while-Schleife.
while B:
S
if C:
T
if D:
U
else:
continue
V
W
while B:
S
if C:
T
else:
U
break
V
else:
W
Dabei sind B, C, D Bedingungen, und S, T, . . . steht für Anweisungen oder Folgen von
Anweisungen. (Die else-Klausel der while-Schleife wird ausgeführt, wenn die Schleife wegen der Bedingung B verlassen wird und nicht durch die break-Anweisung.)
21. Ägyptische Multiplikation, 14 Punkte
(a) Beweisen Sie die partielle Korrektheit der ägyptischen Multiplikation (Aufgabe 17 vom 3. Blatt) mit dem Hoare-Kalkül unter der Annahme a0 , b0 ≥ 0. (Sie
dürfen dabei das Programm leicht umschreiben, ohne die Bedeutung zu ändern;
zum Beispiel können Sie bei der Anweisung a=a//2 eine Fallunterscheidung machen, ob a gerade oder ungerade ist.) Geben Sie jedesmal an, welche Regeln des
Hoare-Kalküls Sie verwenden.
(b) Beweisen Sie die totale Korrektheit.
22. Suche, 8 Punkte, Programmieraufgabe
(a) Schreiben Sie eine einfache Python-Funktion finde nach der folgenden durch
Vor- und Nachbedingungen ausgedrückten Spezifikation. Verwenden Sie nicht
einfach die eingebaute Methode (Funktion) index oder die Abfrage n in A“.
”
{ type(A) = list }
i = finde(A,n)
{ (type(i) = int ∧ A[i] = n) ∨ (i = None ∧ ∀j : 0 ≤ j < len(A) ⇒ A[j] 6= n) }
(b) Schreiben Sie die Funktion so um, dass sie nur mit while-Schleifen auskommt.
(Eventuell müssen Sie in einer späteren Aufgabe die Korrektheit des Programms
beweisen.)
23. Tribonacci-Zahlen, 0 Punkte
Erweitern Sie die Funktion Tr(n) aus der Vorlesung vom 25. April1 so, dass sie
die Tribonacci-Zahlen Tn auch für auch für negative Parameter n berechnet (und
nicht bloß 0 ausgibt). Das Ergebnis soll so definiert sein, dass die Gleichung Tn+1 =
Tn + Tn−1 + Tn−2 für alle ganzen Zahlen n gilt.
1
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/tribonacci.py
7
Algorithmen und Programmierung 2, SS 2016 — 5. Übungsblatt
Abgabe bis Freitag, 20. Mai 2016, 12:00 Uhr
24. Arithmetische Ausdrücke, 12 Punkte, Programm berechne aus der Vorlesung1
(a) (4 Punkte) Kann der Stapel bei der Auswertung eines arithmetischen Ausdrucks
zwischendurch jemals den Inhalt ( 1 + 2 * ( 3 + 4 * ( haben? Kann er
jemals den Inhalt 1 + 2 * 3 (ohne Klammern!) haben? Wie ist es mit den
Inhalten ( 1 * * ( und ( 1 * 2 + ( 3 * 4 + ( ? Wenn ja, zeigen Sie eine
Eingabe, die zu diesem Inhalt führt, wenn nein, begründen Sie Ihre Antwort.
(b) (4 Punkte) Gibt es ungültige arithmetische Ausdrücke, die nicht zu einer Fehlermeldung führen? (Wie bei allen Aufgaben ist die Antwort zu begründen.)
(c) (4 Punkte) Das Programm wurde in der Vorlesung ohne großes Nachdenken entwickelt. Argumentieren Sie mit Hilfe einer passenden Schleifeninvariante (zum
Beispiel: Wie kann der Stapelinhalt aussehen?), dass das Programm korrekt ist,
oder finden Sie ein Beispiel, bei dem das Programm versagt.
25. Partielle Korrektheit, 8 Punkte
(a) (4 Punkte) Die folgende Funktion2 verteilt die Elemente von zwei Listen neu.
Beweisen Sie mit dem Hoare-Kalkül, dass die beiden Listen am Ende dieselbe
Summe haben, wenn das Programm für diese Eingabelisten terminiert.
def Ausgleich(s1, s2):
"""Gleiche zwei Listen aus, sodass sie die gleiche Summe haben.
s1 und s2 sind Listen mit positiven ganzen Zahlen."""
assert all(x>0 and isinstance(x,int) for x in s1+s2)
while sum(s1)!=sum(s2):
if sum(s1) > sum(s2):
a = s1.pop()
s2.append(a)
else:
a = s2.pop()
s1.append(a)
return s1, s2
(b) (4 Punkte) Warum ist in dem Programm trotzdem der Wurm drin?
26. Endrekursion, Programmieraufgabe, 10 Punkte
Eliminieren Sie die Rekursion aus folgender Funktion3 ohne Verwendung eines Stapels. Gehen Sie dabei schematisch nach der Methode aus der Vorlesung vor. Erstellen
Sie als Zwischenschritt eine Lösung mit goto-Anweisungen, bevor Sie als Endprodukt
ein gültiges Python-Programm schreiben.
def fak(n, s=1):
if n<0:
raise ValueError("negatives Argument",n)
if n==0:
return s
return fak(n-1, s*n)
1
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/ausdruecke.py
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/Ausgleich.py
3
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/Fakultaet.py
2
6
Algorithmen und Programmierung 2, SS 2016 — 6. Übungsblatt
Abgabe bis Freitag, 27. Mai 2016, 12:00 Uhr
Liebe Studierende! Das KVV-System bietet die Möglichkeit, dass Sie die Lösungen Ihrer
Mitstudierenden bewerten und durch das Lesen von anderen Lösungen und den Vergleich
mit Ihrer eigenen Lösung ein andersartiges Lernerlebnis erfahren. Wir wollen das bei Aufgabe 28 zum ersten Mal ausprobieren. Ihre Teilname am Bewertungsverfahren wird mit
Übungspunkten honoriert. In der Vorlesung am Mittwoch, den 25. Mai erfahren Sie genaueres zum Ablauf, und es wird auch schriftliche Anleitungen und Hilfestellungen geben.
27. Objekte und Klassen, 8 Punkte
Definieren Sie folgende Begriffe in 1–2 Sätzen, und illustrieren Sie sie jeweils mit
einem kurzes Programmbeispiel in Python.
(a) Objekt (Exemplar) einer Klasse
(c) Aufruf einer Methode
(b) Vererbung
(d) Unterklasse und Oberklasse
(c) Überschreiben von Attributen und Methoden
28. Wettrennen, 15 Punkte
(a) Definieren Sie eine Unterklasse Verfolger von Turtle, die bei der Konstruktion
eine Zielschildkröte als Parameter erhält: t=Verfolger(ziel). Mit der Methode
t.verfolge(Schrittweite) soll t einen Schritt der Länge Schrittweite auf
das Ziel zu machen.
(b) Definieren Sie eine Klasse Rechteck mit dem Konstruktionsaufruf
Rechteck(l,r,u,o)
und einer Methode zeichne, die das Rechteck zeichnet.
(c) Verändern Sie die Klasse Wegläufer aus der Vorlesung, sodass sie bei der Konstruktion ein Rechteck als zusätzlichen optionalen Parameter Begrenzung akzeptiert:
def __init__(self, wovor, Begrenzung=None):
Die Methode lauf_weg soll so modifiziert werden, dass die Schildkröte das
Rechteck nicht verlässt, sich aber dabei innerhalb der Schrittweite möglichst
weit weg vom gefürchteten Verfolger bewegt.
Sie müssen den letzen Satz dieser Vorgabe nicht buchstäblich umsetzen; aber die
Schildkröte darf nicht einfach stehenbleiben, wenn sie am Rand der Begrenzung
ist. Spezifizieren Sie genau, was Ihre Wegläufer-Schildkröte in jedem Fall macht.
Schreiben Sie die Spezifikation als Kommentar in Ihr Programm.
Vorerst sollen Sie bei der Bearbeitung dieser Aufgabe bloß folgendes beachten: Die Bewertung soll anonym erfolgen; schreiben also keine Namen in die Dateien, und nennen Sie Ihr Programm bloß Aufgabe27.py, abweichend von den generellen Vorgaben.
Kommentieren Sie besonders gut, damit Ihr Programm angenehm zu begutachten ist.
29. Knobelaufgabe, 0 Punkte
Stellen Sie mit den Zahlen 1, 5, 6, 7 und den Grundrechnungsarten +, −, ×, / die Zahl
21 dar. Jede Zahl muss genau einmal verwendet werden. Klammern sind erlaubt,
aber Tricks, wie zum Beispiel 15 aus 1 und 5 zu bilden, sind verboten.1
1
Die meisten von Ihnen werden das Problem schneller mit dem Computer durch Probieren aller Möglichkeiten lösen als per Hand.
7
30. (a) Jäger und Beute, 0 Punkte
Ein Adler A mit Geschwindigkeit 2 möchte möglichst schnell zwei Spatzen S1
und S2 fangen. Die Spatzen fliegen stets mit konstanter Geschwindigkeit 1 von
der aktuellen Position des Adlers weg. Der Adler könnte zunächst gradlinig den
näheren der beiden Spatzen fangen und von dort aus geradlinig auf den anderen zusteuern. Schreiben Sie ein Programm, dass dieses Verhalten mit kleinen
Zeitschritten simuliert und graphisch visualisiert.
(b) (Forschungsaufgabe, Antwort unbekannt) Ist diese Strategie immer optimal?
Können Sie Ausgangspositionen finden, wo es eine schnellere Strategie gibt?
31. Objekte und Referenzen, 7 Punkte
Was ist die Ausgabe von untenstehendem Programm? Erklären Sie, was passiert. Wie
kann man am Ende auf das Element ’88’ zugreifen?
def f1(a):
a = a + [a]
def f2(a):
b = a
b.append(7)
def f3(a):
b = a + [’88’]
a.append([a,b])
a=[4,5,6]
f1(a)
print(a)
f2(a)
print(a)
f3(a);print(a)
32. Elimination von goto-Anweisungen, 0 Punkte
Das nebenstehende Programm wurde 1962 in der
Programmiersprache Algol 60 veröffentlicht2 und
von mir fast eins-zu-eins nach Python übersetzt.
Das Programm funktioniert so:
Each call of PERM changes the order of the
first n components of x, and n! successive
calls will generate all n! permutations. The
parameter ‘first’ must be True when PERM
is first called, to cause proper initialization.
Successive calls must leave first = False. On
exit from the (n!)-th call of PERM, the function returns True.
Obwohl es damals schon for- und while-Schleifen
gab, sehen Sie noch jede Menge goto-Anweisungen.
def PERM(x,n,first=False):
global p,d
done = False
if first then
initialize:
p = (n+1)*[0]
d = (n+1)*[1]
k=0
INDEX:
p[n] = q = p[n] + d[n]
if q == n:
d[n] = -1
go to LOOP
if q != 0:
go to TRANSPOSE;
d[n] = 1
k = k + 1
LOOP:
if n > 2:
n = n - 1
go to INDEX
Final exit:
q = 1
done = True
TRANSPOSE:
q = q + k
x[q-1],x[q] = x[q],x[q-1]
return done
"end PERM;"
(a) Bringen Sie das Programm in eine vernünftige Struktur. Den Bezug auf globale
Variablen und die Aufrufkonventionen können Sie unverändert lassen.
(b) Verstehen Sie, was das Programm macht.
2
H. F. Trotter, Algorithm 115: PERM, Communications of the ACM 5 (1962), 434–435.
doi:10.1145/368637.368660, siehe http://www.inf.fu-berlin.de/lehre/SS16/ALP2/PERM.py
8
Algorithmen und Programmierung 2, SS 2016 — 7. Übungsblatt
Abgabe bis Freitag, 3. Juni 2016, 12:00 Uhr
33. Bubblesort, Programmieraufgabe, 10 Punkte
Betrachten Sie folgendes Python-Programm, das eine Liste mit Zahlen bekommt
und die Zahlen innerhalb dieser Liste aufsteigend sortiert. Verwandeln Sie die forSchleife in eine while-Schleife und überlegen Sie sinnvolle Invarianten für beide
while-Schleifen, aus denen die Korrektheit des Sortierprogramms hervorgeht. Warum
muss man die Sortierung nur bis Ende überprüfen? Testen Sie Ihre Invarianten durch
Einfügen von assert-Anweisungen an allen relevanten Stellen. Sie dürfen innerhalb
der assert-Anweisungen selbstdefinierte Hilfsfunktionen verwenden wie zum Beispiel
eine Funktion, die überprüft, ob eine Liste sortiert ist (Aufgabe 19).
def bubblesort (A):
Ende = len(A)-1
while Ende>0:
letzteÄnderung = 0
for i in range(Ende):
if A[i]>A[i+1]:
A[i], A[i+1] = A[i+1], A[i]
letzteÄnderung = i
Ende = letzteÄnderung
34. O-Notation, 5 Punkte
Gegeben sind zwei positive Funktionen S, T : N → R>0 . Beweisen Sie: Aus S(n) =
O(f (n)) und T (n) = O(g(n)) folgt, dass S(n) · T (n) = O(f (n)g(n)) ist.
35. Vergleich von asymptotischen Laufzeiten, 0 Punkte
Welche der beiden folgenden Laufzeiten f (n) und g(n) ist für große Werte von n
schneller, und welche für kleine n? Bei welchem Wert von n ändert sich die Antwort?
(a) f (n) = 10n(log2 n)2 , g(n) = 2n3/2
(b) f (n) = 5 · 2n , g(n) = 100n2 log2 n
36. Laufzeitvergleich, 10 Punkte
Die folgende Tabelle gibt die Laufzeiten von verschiedenen Algorithmen für eine
Eingabe der Größe n auf einem bestimmten Rechner an.
Verfahren
Algorithmus
Algorithmus
Algorithmus
Algorithmus
A
B
C
D
Laufzeit in Millisekunden
0,001n!
0,01n2
0,1 n log2 n
0,5n
Programmieraufwand
1 Stunde
1 Tag
1 Woche
10 Wochen
Welchen Algorithmus würden Sie empfehlen, wenn das Programm für Eingaben der
Größe (a) n = 10, (b) n = 1000, (c) n = 10 000 000 bis zum Jahr 2025 (i) einmal pro
Jahr, (ii) täglich, (iii) 10-mal pro Sekunde laufen müsste.
• (5 Punkte) Untersuchen Sie die Szenarien (b)+(iii), (a)+(i), und (c)+(ii).
• (5 Punkte) Was ändert sich für diese Szenarien, wenn man auf eine zehnmal
schnellere Hardware umsteigt?
37. Wettrennen (5 Punkte): Bewerten Sie zwei Lösungen von Aufgabe 28 im KVV.
9
Algorithmen und Programmierung 2, SS 2016 — 8. Übungsblatt
Abgabe bis Freitag, 10. Juni 2016, 12:00 Uhr
38. Stabile Sortierverfahren, 10 Punkte
Ein Sortieralgorithmus ist stabil, wenn es gleiche Werte in derselben relativen Reihenfolge belässt, in der sie in der Eingabe stehen. Bewerten Sie die Verfahren (i) Bubblesort (ii) Sortieren durch Verschmelzen (iii) Sortieren durch Einfügen und (iv) Quicksort bezüglich ihrer Stabilität. Es stehen folgende Antworten zur Auswahl.
(a) Man kann gar nicht vermeiden, dass das Verfahren stabil ist.
(b) Das Verfahren ist stabil, wenn man bei der Programmierung darauf achtet.
(c) Das Verfahren kann nur mit Mühe stabil gemacht werden.
Begründen Sie Ihre Antworten. Im Fall (b) geben Sie Beispiele, was man falsch machen kann. Im Fall (c) geben Sie ein Beispiel, wo der Algorithmus nicht stabil ist.
39. Umrechnungstabelle, Programmieraufgabe, 10 Punkte
(8 Punkte) Schreiben Sie ein Programm, das bei Eingabe einer Währung und eines
Wechselkurses eine schlaue Umrechnungstabelle für eine Auslandsreise nach folgendem Muster berechnet, und das ohne Sortieren auskommt. Alle Beträge, die zwischen
1 und 100 Euro ausmachen und die in einer der Währungen eine “runde Zahl” ergeben, sollen darin enthalten sein. (Die Aufteilung in drei Spalten ist nicht notwendig.)
313.81
500.00
627.62
1000.00
1569.06
HUF
HUF
HUF
HUF
HUF
=
=
=
=
=
1.00
1.59
2.00
3.19
5.00
EUR
EUR
EUR
EUR
EUR
2000.00
3138.12
5000.00
6276.24
HUF
HUF
HUF
HUF
= 6.37 EUR
= 10.00 EUR
= 15.93 EUR
= 20.00 EUR
10000.00
15690.60
20000.00
31381.20
HUF
HUF
HUF
HUF
= 31.87
= 50.00
= 63.73
= 100.00
EUR
EUR
EUR
EUR
(2 Punkte) Wieviele Einträge enthält die Tabelle höchstens und mindestens?
(Zusatzfrage, 0 Punkte.) Bei welchem Wechselkurs wird die größte relative Lücke
(das heißt, das Verhältnis zwischen aufeinanderfolgenden Einträgen) am kleinsten?
40. Logarithmen, 0 Punkte. In der Vorlesung wurde gezeigt, dass Quicksort im durchschnittlichen Fall weniger als 2(n+1)·Hn ≤ 2(n+1)(1+ln n) = O(n log n) Vergleiche
benötigt. Warum muss man beim Logarithmus in der O-Notation nicht angeben, zu
welcher Basis der Logarithmus gemeint ist?
41. Sortieren durch Verschmelzen von klein auf“ (bottom-up mergesort), 10 Punkte
”
Bei diesem Verfahren wird nicht rekursiv zerlegt, sondern es werden immer längere
sortierte Teillisten aufgebaut. Nach i Schritten hat man Teillisten der Länge 2i , bis auf
eine letzte Liste, die möglicherweise kürzer ist. Diese Listen werden dann paarweise
zusammengefasst und verschmolzen.
(a) Untersuchen Sie die exakte Anzahl der Vergleiche im schlimmsten Fall für dieses
Verfahren und für das klassische Sortieren durch Verschmelzen nach dem Teileund-herrsche-Prinzip:
i. Für Eingaben der Länge 2k , für k = 2, 3, 4, 5.
ii. Für Eingaben der Länge 3 · 2k−1 , für k = 2, 3, 4, 5.
iii. Für Eingaben der Länge 2k+1 − 1, für k = 2, 3, 4, 5.
(b) Beweisen Sie, dass die Laufzeit dieses Verfahrens O(n log n) ist.
Diese Aufgabe ist für die wechselseitige Bewertung vorgesehen. Laden Sie die Lösung
daher im KVV hoch, vorzugsweise als PDF-Datei oder ersatzweise als gescannte
Bilddatei (nicht als veränderbare doc-, tex-, rtf- oder odt-Datei), und schreiben Sie
Ihre Namen nicht in die Datei. Eine Abgabe auf Papier ist nicht notwendig.
10
Algorithmen und Programmierung 2, SS 2016 — Probeklausur
Abgabe bis Mittwoch, 8. Juni 2016, 13:45 Uhr
42. Rekursion, 10 Punkte
Die folgende Funktion berechnet die Anzahl der Binärziffern (ohne führende Nullen)
einer natürlichen Zahl n. (Beispiel: n = 23 = (10111)2 7→ 5)
def binaryDigits(n):
if n==0:
return 0
else:
return 1 + binaryDigits(n//2)
(a) Schreiben Sie für diese Aufgabe eine Funktion ohne Rekursion.
(b) Schreiben Sie für diese Aufgabe eine Funktion ohne Division (und ohne irgendwelche Bibliotheksfunktionen).
(Sie können Teil (a) und (b) auch gemeinsam durch eine Funktion lösen.)
(c) Geben Sie die Laufzeit und den Speicherbedarf für die gegebene Funktion und
für Ihre Lösungen an. (Nehmen Sie dabei an, dass jede der vier Grundrechnungsarten (+, −, ∗ und //) mit ganzen Zahlen in O(1) Zeit durchgeführt werden
kann.)
43. O-Notation, 10 Punkte
(a) Gegeben sind zwei positive Funktionen S, T : N → R>0 . Beweisen Sie: Aus
S(n) = Ω(f (n)) und T (n) = Ω(g(n)) folgt, dass S(n) · T (n) = Ω(f (n)g(n))
ist.
(b) Geben Sie einen möglichst einfachen Ausdruck der Form Θ(f (n)) für folgenden
Ausdruck an:
25n2 − 100bn/2c + 365
(c) Geben Sie einen möglichst einfachen Ausdruck der Form Θ(f (n)) für folgenden
Ausdruck an:
23n + 12n log2 n + 1666
3. siehe Rückseite
11
44. Quicksort, 10 Punkte
Das folgende Python-Programm ordnet einen Abschnitt a[l : r] einer Liste a um
und zerlegt ihn in drei Teile a[l : i − 1], a[i], und a[i + 1 : r], sodass alle Elemente im
ersten Teil ≤ a[i] sind und alle Elemente im dritten Teil ≥ a[i] sind.
def zerlege(a,l,r):
"""Zerlege a[l:r]=a[l],a[l+1],...,a[r-1] für Quicksort
Voraussetzung 1: l<r
Voraussetzung 2: a[r] existiert, und a[r] >= a[i] für l<=i<r.
Rückgabewert = i = Position des Pivotelements
"""
pivot = a[l] # a[l] wird als Pivotelement gewählt.
k, g = l+1, r-1
while True:
_______________________________________________________ (1.)
____________________________________________________________
while a[k]<pivot:
k = k+1
while a[g]>pivot:
g = g-1
_______________________________________________________ (2.)
____________________________________________________________
if g<=k:
a[l],a[g]=a[g],pivot
return g
a[k],a[g] = a[g],a[k] # vertausche
_______________________________________________________ (3.)
____________________________________________________________
k = k+1
g = g-1
(a) Fügen Sie an den nummerierten Stellen aussagekräftige Invarianten ein, aus
denen die Korrektheit des Programmes hervorgeht. Sie können dabei mathematische Notation verwenden und brauchen keine Python-Syntax zu beachten.
Zum Beispiel könnte die erste Invariante ungefähr so aussehen:
(1.)
pivot = a[l] ∧ k > l ∧ ∀i : (. . . ) ⇒ a[i] ≤ pivot ∧ . . .
(b) Beweisen Sie, dass das Programm auf keine Listenelemente außer auf
a[l], a[l + 1], . . . , a[r]
zugreift. Sie können dabei auf Ihre Invarianten von Teil (a) zurückgreifen. (Die
Gültigkeit dieser Invarianten brauchen Sie nicht zu beweisen.)
(c) (3 Zusatzpunkte) Beweisen Sie, dass das Programm terminiert.
12
Algorithmen und Programmierung 2, SS 2016 — 10. Übungsblatt
Abgabe bis Freitag, 17. Juni 2016, 12:00 Uhr
45. Klassen, Exemplare, und Attribute, 12 Punkte
Wir erzeugen zwei Exemplare einer Klasse C, die keine eigenen Attribute hat:
class C:
pass -- "leere" Klasse
exemplar1 = C()
exemplar2 = C()
(a) Was passiert, wenn das Objekt exemplar1 danach ein neues Attribut erhält:
exemplar1.a = 2“. Hat das Auswirkungen auf exemplar2? Auf die Klasse C?
”
(b) Was passiert, wenn stattdessen die Klasse C danach ein neues Attribut erhält:
C.a = 4“. Hat das Auswirkungen auf exemplar1 und exemplar2? Auf Exem”
plare von C, die danach erzeugt wurden?
(c) Wie ist es, wenn sowohl (a) als auch (b) für eine Attribut mit dem gleichen
Namen a stattfindet? Kommt es dabei auf die Reihenfolge an? Erklären Sie,
was passiert.
46. Haldensortieren, Programmieraufgabe, 12 Punkte
(a) Ergänzen Sie die Funktionen zugroß(a,i) und zuklein(a,i) aus der Vorlesung
zu lauffähigen Python-Funktionen.
(b) Implementieren Sie damit eine Funktion heapsort(a,n), die die Elemente von
a[:n] aufsteigend sortiert.
47. O-Notation, 6 Punkte
Geben Sie möglichst einfache obere Schranken der Form O(f (n)) und untere Schranken der Form Ω(g(n)) für folgende Funktionen an:
(a) 2blog2 nc
(b) 3blog2 nc
dlog2 log2 ne
(c) 22
48. Laufzeit der Haldenkonstruktion, 0 Punkte
Beweisen Sie (zum Beispiel durch vollständige Induktion nach k, oder indem Sie den
Ausdruck
auf der linken Seite für k und k − 1 hinschreiben und die Differenz bilden):
Pk
i
k+1 − k − 2
i=0 2 (k − i) = 2
49. Asymptotisches Wachstum, 0 Punkte
(a) Beweisen Sie: 125n3 + 2n = Θ(2n )
(Es gilt sogar für alle a und für alle b > 1: na + bn = Θ(bn ). Exponentialfunktion
schlägt jede Potenz.)
Anleitung zu einer möglichen Lösung:
1. Für n ≥ 125 gilt 125n3 ≤ n4 .
2. Die Funktion eu−1 − u ist für u ≥ 1 monoton wachsend. (Ableitung!)
3. Daraus ergibt sich 16u−1 ≥ eu−1 ≥ u für u ≥ 1, und somit 16u ≤ 16u .
4. Für n = 16u ist somit n ≤ 2n/4 und n4 ≤ 2n , falls n groß genug ist.
5. Es gibt eine Schranke n0 , sodass 125n3 ≤ 2n für alle n ≥ n0 gilt.
(b) Beweisen Sie: (log2 n5 )6 + n2 = Θ(n2 ). (Es gilt sogar für alle a, c und für alle
b > 0: c(log2 n)a + nb = Θ(nb ). Potenz schlägt jeden Logarithmus.)
50. (10 freiwillige Zusatzpunkte): Bewerten Sie zwei Lösungen von Aufgabe 41 im KVV.
13
Algorithmen und Programmierung 2, SS 2016 — 11. Übungsblatt
Abgabe bis Freitag, 24. Juni 2016, 12:00 Uhr
51. Verkettete Listen, Programmieraufgabe, 15 Punkte
Modifizieren Sie die Klasse VerketteteListe1 aus der Vorlesung so, dass sie folgende
zusätzliche Methoden unterstützt.
(a) public void einfüge(int i, Knoten k). Fügt einen neuen Knoten mit Wert i
an die Stelle nach dem Knoten k in die Liste ein.
(b) public boolean lösche(). Löscht den ersten Knoten aus der Liste. Wenn die
Liste vorher leer war, soll das Ergebnis false sein, sonst true.
(c) public boolean lösche(Knoten k). Löscht den Knoten k aus der Liste. Wenn
der Knoten k gar nicht zur Liste gehört, soll das Ergebnis false sein, sonst true.
(Diese Operation geht nicht in konstanter Zeit.)
Geben Sie dem Programm den Namen Aufgabe51 Nachname1 Nachname2.java. Die
obligatorische Testsuite soll als main-Methode der Klasse VerketteteListe ablaufen.
52. Arithmetik in Java, 15 Punkte
Arithmetische Operationen werden in Java strikt von links nach rechts ausgerechnet,
sofern Vorrangregeln und Klammern nichts anderes vorgeben. Wenn beide Operanden einer arithmetischen Operation vom Typ int, long, float oder double sind, hat
das Ergebnis denselben Typ; bei gemischten Operanden wird ein Operand vorher in
den allgemeineren“ Typ umgewandelt (int → long → float → double). Gleit”
kommakonstanten wie 0.1 werden immer als double-Werte interpretiert. Werte vom
Typ int liegen im Intervall [−231 , 231 − 1], und ganzzahlige Aritmetik mit solchen
Werten wird immer modulo 232 ausgeführt.
P
Die folgende Funktion zeigt acht verschiedene Arten, die Summe ni=1 1/i2 zu berechnen, die für n → ∞ (langsam) gegen π 2/6 konvergiert.
static double Summe(int
double s = 0.0;
float eins = 1;
for (int i=1; i<=n;
 s +=



s +=




s +=



s +=
Varianten
 s +=




s +=




 s +=
s +=
return s;
}
n) {
i++)
1/i*i;
1/(i*i);
1.0/i/i;
1.0/(i*i);
1.0/((double)(i)*i);
1/(double)(i*i);
eins/i/i;
1/(1.0*i*i);
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
Testen Sie jede einzelne dieser Varianten jeweils für n = 100, 10 000, 106 , 108 und
109 und vergleichen Sie das Ergebnis mit dem Grenzwert. Erklären Sie, was passiert.2 Formulieren Sie eine Vermutung, wie groß ungefähr der Abstand zwischen
dem Grenzwert und der (exakten) Summe der ersten n Glieder ist.
1
2
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/VerketteteListe.java
https://de.wikipedia.org/wiki/IEEE_754#Unendlich
14
Algorithmen und Programmierung 2, SS 2016 — 12. Übungsblatt
Abgabe bis Freitag, 1. Juli 2016, 12:00 Uhr (Aufgabe 53 korrigiert am 7. Juli)
53. Verkettete Liste mit Zeiger zum Listenende, Programmieraufgabe, 10 Punkte
Erweitern Sie die Klasse VerketteteListe von Aufgabe 51, indem Sie eine Unterklasse VerketteteSchlange erstellen, die die folgenden zusätzlichen Operationen in
konstanter Zeit unterstützt.
(a) public void anhängen(int i). Fügt einen neuen Knoten mit Wert i am Ende
der Liste ein.
(b) public void anhängen(VerketteteSchlange L2). Hängt die verkettete Liste
L2 an das Ende der Liste an und vereinigt somit die beiden Listen zu einer Liste.
Die neue Klasse soll auch alle bisherigen Operationen weiterhin unterstützen. Dazu
müssen Sie gegebenenfalls die alten Methoden überschreiben. Verwenden Sie dabei
möglichst viele Methoden der ursprünglichen Klasse, indem Sie zum Beispiel etwa
super.einfüge() aufrufen, und programmieren Sie nur das neu, was nötig ist. Achten Sie darauf, dass die Operationen auch bei leeren Listen korrekt funktionieren.
54. Zusatzfrage, 0 Punkte
Kann man die Liste L2 noch verwenden, nachdem sie in der Methode anhängen von
Aufgabe 53b verbraucht“ worden ist?
”
55. Turm von Hanoi, Programmieraufgabe, 10 Punkte
Schreiben Sie ein Java-Programm, das den Turm von Hanoi löst. Verwenden Sie dafür
die Klasse hanoi.Turm aus dem Paket hanoi1 Die drei Stifte sind mit ’a’, ’b’, und
’c’ bezeichnet. Das Programm TestTurm2 zusammen mit der Klasse HanoiLoesung3
zeigt ein Beispiel, wie die Klasse Turm verwendet wird. In der Klasse Turm sind folgende Methoden implementiert (siehe Aufgabe 58b für die Bedeutung von final“):
”
package hanoi;
public class Turm {
public Turm(int [] anfangsturm) throws TurmException
/** anfangsturm enthält die Größen aller Scheiben, aufsteigend sortiert.
Gleiche Scheiben sind erlaubt. Die Scheiben werden auf Stift ’a’ gesetzt. */
public final int setzeUm(char s, char z) throws TurmException; { . . .
/** bewegt die oberste Scheibe vom Stift s (Start) zum Stift z (Ziel).
Vorbedingungen:
• s, z = ’a’, ’b’, oder ’c’, und s 6= z.
• Stift s ist nicht leer.
• Oberste Scheibe d auf Stift s ≤ oberste Scheibe auf z, oder z ist leer.
Der Rückgabewert ist d.
*/
}
public final boolean fertig(); // testet, ob die Stifte ’a’ und ’b’ leer sind
public int[] anfangsturm();
// erstellt eine Kopie des Ausgangsturms
public final int bewegungen(); // die Anzahl der bisherigen Bewegungen
}
1
Speichern Sie die Dateien Turm.class und TurmException.java von http://www.inf.fu-berlin.de/
lehre/SS16/ALP2/hanoi/ in ein Unterverzeichnis mit Namen hanoi.
2
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/TestTurm.java
3
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/HanoiLoesung.java
15
Schreiben Sie Ihre eigene Klasse HanoiLoesung, die mit der Methode anfangsturm
den Turm untersucht und anschließend die korrekte Folge von Bewegungen durchführt.
(Diese Klasse wird dann von einem Testprogramm aufgerufen, das ähnlich wie das
Programm TestTurm arbeitet. Schreiben Sie trotzdem Ihre eigene Testsuite.)
56. Schnittstellen, 0 Punkte
Schreiben sie eine Schnittstelle interface TurmInterface für Klassen, die die Methoden von Turm von Aufgabe 55 unterstützen.
57. Generische Methoden, Programmieraufgabe, 10 Punkte
Außer Klassen können auch Methoden in Java mit einem Datentypen parametrisiert
werden. Schreiben Sie eine generische statische Methode swap, die zwei gegebene
Elemente eines Feldes miteinander vertauscht:
class Swap {
public static <T> void swap(...) ... Definition von swap ...
public static void main(String[] args) {
Integer [] a = {1,2,0,2,3};
Swap.<Integer>swap(a, 2, 3); // vertauscht a[2] mit a[3]
swap(a, 0, 4); // auch ohne explizite Angabe des Datentyps
// Der Typ wird aus dem Argument a erschlossen. (Typinferenz)
}
}
58. Endgültige Klassen, 0 Punkte
(a) Studieren Sie den Quellcode Turm.java4 , der eine mögliche Implementierung der
Klasse Turm zeigt. Gibt es eine Möglichkeit das Testprogramm von Aufgabe 55
zu überlisten, sodass man auch mit einer falschen Lösung erreichen kann, dass
fertig() am Ende den Wert true zurückgibt?
(b) Nehmen wir an, wir dürfen die Klasse Turm erweitern und die Methode
HanoiLoesung.löse(t)
auch mit einer Unterklasse von Turm aufrufen. Methoden, die als final“ de”
klariert werden, können von einer Unterklasse nicht überschrieben werden. Gibt
es trotzdem einen Weg, das Testprogramm zu überlisten?
(c) Kann man auch erreichen, dass die Methode bewegungen nicht die korrekte Zahl
an Aufrufen von setzeUm meldet?
(d) Wie kann man diese Schlupflöcher gegebenenfalls stopfen?
(e) Warum ist es nicht notwending, die Methode anfangsturm als final zu deklarieren? Warum wurde der Konstruktor Turm nicht als final deklariert?
59. Die Collections-Klassen von Java, 0 Punkte
Studieren Sie die Dokumentation der Klasse PriorityQueue5 und finden Sie eine
möglichst einfache Möglichkeit, mit Hilfe der Methoden und Klassen des CollectionRahmens die Elemente einer Prioritätswarteschlange pq in absteigend sortierter Reihenfolge auszudrucken,
(a) wenn die Prioritätswarteschlange pq dabei nicht verändert werden soll,
(b) wenn die Prioritätswarteschlange pq danach nicht mehr gebraucht wird.
4
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/Turm.java
siehe zum Beispiel http://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html,
http://docs.oracle.com/javase/tutorial/collections/intro/, oder
http://docs.oracle.com/javase/tutorial/collections/interfaces/queue.html.
5
16
Algorithmen und Programmierung 2, SS 2016 — 13. Übungsblatt
Abgabe bis Freitag, 8. Juli 2016, 12:00 Uhr
60. Verallgemeinerter Turm von Hanoi, Programmieraufgabe, 11 Punkte.
Untersuchen Sie die Variante des Turmes von Hanoi, bei dem auch gleich große Scheiben erlaubt sind. Gleiche Scheiben dürfen übereinander liegen, aber eine Scheibe darf
nach wie vor nicht über einer kleineren Scheibe liegen.
Überlegen Sie, wie die Lösung für den klassischen Fall hergeleitet wird und warum
diese Lösung optimal ist. Verallgemeinern Sie Ihre Überlegung für den Fall gleich
großer Scheiben.
Schreiben Sie eine Klasse HanoiLoesungVerallgemeinert, die die optimale Bewegungsfolge für diesen Fall berechnet. Zum Beispiel soll der Aufruf
int[] a = {1,2,2,2};
HanoiLoesungVerallgemeinert.löse(new Turm(a));
das Problem mit 5 Bewegungen lösen.
61. Binärbäume, Rekursion, 5 Punkte
Schreiben Sie (auf Papier) ein Java-Programm, das die Anzahl der Knoten in einem
Binärbaum bestimmt, der durch folgende Klasse definiert ist.
class Binärbaum <T> {
T wert;
Binärbaum <T> links, rechts; // Kinder
...
}
62. Radixsort und Sortieren durch Fachverteilung, Programmieraufgabe, 14 Punkte.
Programmieren Sie das Verfahren RadixSort zum Sortieren einer verketteten Liste
von ganzzahligen int-Werten mit 32 Bits in linearer Zeit. Zerlegen Sie dazu die intWerte x in vier Ziffern“ zu je 8 Bits. Diese Ziffern liegen im Bereich 0–255 und
”
können durch Bitverschiebungen und Bitmasken aus x bestimmt werden: x & 0xff,
(x>>>8)&0xff, (x>>>16)&0xff, und (x>>>24).
Zum stabilen Sortieren nach einer Ziffer verwenden wir nicht Sortieren durch Zählen
(Countingsort), sondern folgende Methode, die für verkettete Listen L mit n Elementen besser geeignet ist: Wir erstellen ein Feld von 256 leeren Listen T0 , . . . , T255 ; dann
durchlaufen wir L in O(n) Zeit und verteilen die Elemente auf diese Listen, indem
wir jedes Element x am Ende der Teilliste Ti anhängen, wenn die rechteste Ziffer
von x den Wert i hat. Danach verketten wir die Listen T0 , . . . , T255 zu einer neuen
Gesamtliste L0 und wiederholen das Verfahren für die zweite Ziffer von rechts, usw.
Am Ende, bei der linkesten Ziffer, müssen wir zuerst die Fächer T128 , T129 , . . . , T255
zusammenhängen und anschließend die Fächer T0 , T1 , . . . , T127 , damit das Vorzeichen
richtig berücksichtigt wird und die negativen Zahlen vor den positiven kommen.
(a) Schreiben Sie ein Programm für diesen Sortieralgorithmus. Benützen Sie für die
Teillisten Ihre Lösung von Aufgabe 53. Zum Einlesen ganzer Zahlen von der
Konsole oder aus einer Datei können Sie die Klasse IntReader1 verwenden.
(b) Zusatzfrage, 0 Punkte. Das Sortieren nach jeder Ziffer muss eigenlich stabil sein.
Kann man trotzdem für die Teillisten auch Stapel statt Schlangen verwenden?
1
http://www.inf.fu-berlin.de/lehre/SS16/ALP2/IntReader.java
17
Algorithmen und Programmierung 2, SS 2016 — 14. Übungsblatt
Freiwillige Abgabe bis Freitag, 15. Juli 2016, 12:00 Uhr
63. Sortierte Reihenfolge, Programmieraufgabe, 5 Punkte
Schreiben Sie ein Java-Programm istSortiert zum Testen, ob ein binärer Baum ein
Suchbaum ist: Für jeden Knoten k mit Schlüssel (wert) x muss gelten: Alle Schlüssel
im linken Teilbaum von k sind kleiner als x; alle Schlüssel im rechten Teilbaum von k
sind größer als x.
Verwenden Sie bei dieser und bei den beiden folgenden Aufgaben die Konvention
von Aufgabe 61. Ihr Programm soll nur lineare Zeit brauchen. Sie dürfen zusätzliche
Datenstrukturen zu Hilfe nehmen.
5 Zusatzpunkte gibt es für ein Programm, das ohne zusätzliche Datenstrukturen
auskommt. Rekursion dürfen Sie verwenden.
64. Haldenordnung, Programmieraufgabe, 5 Punkte
Schreiben Sie ein Java-Programm istHalde zum Testen, ob ein binärer Baum die
Haldeneigenschaft erfüllt: Die Kinder jedes Knotens k müssen einen größeren Wert
haben als k.
65. Niveau-Reihenfolge, Programmieraufgabe, 0 Punkte
Schreiben Sie ein Java-Programm, das die Knoten eines Binärbaumes in NiveauReihenfolge ausgibt, das heißt, nach Tiefe sortiert: Zuerst kommt die Wurzel, dann
die Kinder der Wurzel von links nach rechts, usw. Ihr Programm soll nur lineare Zeit
brauchen. Sie dürfen zusätzliche Datenstrukturen zu Hilfe nehmen. (Die Tiefe eines
Knotens ist der Abstand zur Wurzel. Die Höhe eines Baumes ist die größte Tiefe
eines Knotens.)
66. Supermarktkassen, Programmieraufgabe, 2 × 5 Punkte
Modifizieren Sie das Simulationsprogramm aus der Vorlesung, sodass es folgende
Varianten behandelt:
(a) Es gibt nur eine gemeinsame Schlange für alle Kassen.
(b) Es gibt eine getrennte Schlange für jede Kasse. Neu ankommende Kunden stellen
sich bei der kürzesten Schlange an. Wenn mehrere Schlangen die gleiche Länge
haben, dann wird die erste“ Schlange (mit der kleinsten Nummer) gewählt.
”
67. (0 Punkte) Stellen Sie die Hierarchie aller Klassen und Schnittstellen des Programms
Simulation dar.
68. Verständnisfragen, 10 Punkte
(a) Wann muss man einen eigenen Konstruktor für eine Unterklasse schreiben und
kann nicht automatisch den Konstruktor für die Oberklasse übernehmen?
(b) Welche Vorteile haben generische Klassen und generische Methoden.
(c) Warum muss die main-Methode in Java als statische Methode definiert sein?
(d) Warum kann es vorteilhaft sein, eine geschachtelte Klasse innerhalb einer anderen Klasse zu definieren, statt auf der äußersten Ebene (der Paketebene)?
(e) Warum kann man die Klasse Ereignis im Programm Simulation.java nicht
einfach ohne die Methode bearbeite definieren, statt Ereignis als abstrakte
Klasse zu definieren?
(f) Was ist der Unterschied zwischen dem Überschreiben und dem Überladen von
Methoden?
18
Algorithmen und Programmierung 2, SS 2016 — Klausur
Abgabe bis Montag, 18. Juli 2016, 16:00 Uhr
69. Typumwandlung und Konstruktoren in Java, 10 Punkte
(a) (6 Punkte) Die Variablen i, f, d seien so deklariert:
int i; float f; double d;
Welche der folgenden drei Anweisungen sind korrekt?
i = f * d; // 1.
d = i * f; // 2.
f = i * d; // 3.
Erläutern Sie für jede gültige Anweisung genau, was passiert. Welche Größe wird
wann in welchen Typ umgewandelt?
Ergänzen Sie die ungültigen Anweisungen durch explizite Typumwandlungen
so, dass sie gültig werden. (Eventuell gibt es mehrere korrekte Möglichkeiten.)
(b) (4 Punkte) Welche der folgenden Aussagen über Konstruktoren sind richtig?
Geben Sie im positiven Fall ein Beispiel von Klassen mit einem Aufruf eines
solchen Konstruktors an.
i. Eine Unterklasse erbt automatisch alle Konstruktoren der Oberklasse.
ii. In einem Konstruktor kann man einen anderen Konstruktor derselben Klasse aufrufen.
70. Binärbäume, 10 Punkte
Ergänzen Sie die folgende Klassendefinition von Binärbaum in Java durch eine Methode, die die Höhe eines Binärbaums bestimmt.
class Binärbaum <T> {
T wert;
Binärbaum <T> links, rechts; // Kinder
...
}
Die Höhe ist die Länge des längsten Weges von der Wurzel zu einem Blatt. Ein Baum
mit einem einzigen Knoten hat also Höhe 0. Für den leeren Baum, der durch null
dargestellt wird, legen wir fest, dass die Höhe −1 sein soll.
71. O-Notation, 10 Punkte
(a) (4 Punkte) Gegeben sind zwei positive Funktionen S, T : N → R>0 . Beweisen
Sie: Aus S(n) = Ω(f (n)) und T (n) = Ω(g(n)) folgt, dass S(n)+T (n) = Ω(f (n)+
g(n)) ist.
(b) (3 Punkte) Geben Sie einen möglichst einfachen Ausdruck der Form Θ(f (n))
für folgenden Ausdruck an. Eine Begründung ist nicht erforderlich.
a(n) = 3n3 + 25n2 + 100 · 2n + 65
(c) (3 Punkte) Geben Sie einen möglichst einfachen Ausdruck der Form Θ(f (n))
für folgenden Ausdruck an. Eine Begründung ist nicht erforderlich.
b(n) = 3n3 + 10n + 66 log2 n + 16
19
72. Verschmelzen, 10 Punkte
Das folgende Python-Programm verschmelzt zwei sortierte Listen von Zahlen a
und b zu einer gemeinsamen sortierten Liste c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def verschmelze(a,b):
"""
Voraussetzung 1: a und b sind Listen von Zahlen
Voraussetzung 2: a ist sortiert: a[i] <= a[i+1] für 0<=i<len(a)-1
Voraussetzung 3: b ist sortiert: b[i] <= b[i+1] für 0<=i<len(b)-1
"""
m = len(a)
n = len(b)
c = [0] * (m+n) # erzeugt eine Liste der Länge m+n
i = j = k = 0
while k<m+n:
assert(...) _____________________________ (1.)
if i==m or (j<n and a[i]>b[j]):
assert(...) _________________________ (2.)
c[k] = b[j]
j = j+1
k = k+1
else:
assert(...) _________________________ (3.)
c[k] = a[i]
i = i+1
k = k+1
assert(...) _____________________________ (4.)
return c
(a) (6 Punkte) Fügen Sie an den nummerierten Stellen aussagekräftige Invarianten
ein, aus denen die Korrektheit des Programmes hervorgeht. (Schreiben Sie die
Invarianten nicht auf dieses Blatt, sondern in die Klausurblätter.) Sie können dabei mathematische Notation mit Python-Syntax mischen. Zum Beispiel könnte
die erste Invariante ungefähr so beginnen:
(1.)
c[:k] enthält die gleichen Elemente wie a[:i] + b[:j] ∧
m = len(a) ∧ isSorted(c[:k]) ∧ k ≥ 0 ∧ . . .
wobei das Prädikat isSorted so definiert ist:
isSorted(L) ⇐⇒
∀u : (0 ≤ u < len(L) − 1) ⇒ L[u] ≤ L[u + 1]
Die Gültigkeit der Invarianten brauchen Sie nicht zu beweisen. Bedingungen,
die an mehreren Stellen gelten, sollten Sie zweckmäßigerweise zusammenfassen
und mit einer Abkürzung bezeichnen.
(b) (4 Punkte) Begründen Sie unter Zuhilfenahme Ihrer Invarianten, dass in den Listenzugriffen wie a[i] oder c[k] keine Listenindizes außerhalb der Listengrenzen
auftreten.
(c) (3 Zusatzpunkte) Beweisen Sie, dass die Funktion terminiert.
20
Herunterladen