10. Übungsblatt

Werbung
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
Prof.aa
Dr. J. Giesl
M. Brockschmidt, F. Emmes, C. Fuhs, C. Otto, T. Ströder
Allgemeine Hinweise:
•
Die Hausaufgaben sollen in Gruppen von je 2 Studierenden aus der gleichen Kleingruppenübung bearbeitet werden. Namen und Matrikelnummern der Studierenden sind auf jedes Blatt der Abgabe zu schreiben.
Heften bzw. tackern Sie die Blätter!
•
•
Die Nummer der Übungsgruppe muss links oben auf das erste Blatt der Abgabe geschrieben werden.
Die Lösungen müssen bis Donnerstag, den 19.01.2012 um 17:30 Uhr in den entsprechenden Übungskasten
eingeworfen werden. Sie nden die Kästen am Eingang Halifaxstr. des Informatikzentrums (Ahornstr. 55).
Alternativ können Sie die Lösungen direkt im Tutorium abgeben.
•
Beachten Sie die auf der Webseite veröentlichten Code-Konventionen in Ihren Programmen. Grobe Verstöÿe werden mit Punktabzügen von bis zu 50% geahndet.
•
In einigen Aufgaben müssen Sie in Java programmieren und
.java-Dateien anlegen. Drucken Sie diese aus
und schicken Sie sie per E-Mail vor Donnerstag, den 19.01.2012 um 17:30 Uhr an Ihre Tutorin/Ihren Tutor.
Stellen Sie sicher, dass Ihr Programm von
javac akzeptiert wird, ansonsten werden keine Punkte vergeben.
Tutoraufgabe 1 (Collections):
Collections Framework verwenden,
java.util nden. Auÿerdem benötigen Sie die Klassen Term und Variable von unserer
die Klasse Term eine Oberklasse von Variable. Diese Klassen modellieren mathematische
In dieser Aufgabe sollen Sie nach Möglichkeit vordenierte Klassen aus dem
welches Sie im Package
Homepage. Dabei ist
Terme. Dabei hat jeder Term einen Namen und eine Liste von Argumenten, die wiederum Terme sind. Eine
Variable hat immer eine leere Argumentliste.
Term um eine Methode Set<Variable> createSetOfVariables(), welche eine Menge
Typs Variable zurückliefert. Diese Menge soll genau alle Variablen enthalten, die im aktuellen
Ergänzen Sie die Klasse
von Objekten des
Term vorkommen. Falls der aktuelle Term also eine Variable ist, so enthält diese Menge genau diese Variable.
Ansonsten enthält sie die Vereinigung aller Variablenmengen der Argumente des aktuellen Terms. Nutzen Sie die
Möglichkeit, die Methode
createSetOfVariables()
in der Unterklasse
Variable
zu überschreiben, sodass sie
sowohl auf Variablen als auch auf anderen Termen korrekt arbeitet.
Hinweise:
•
Schauen Sie sich die API des
Collections
Frameworks an, um sich über das
Set
Interface und passende
Implementierungen zu informieren. Hierbei dürfen Sie zur Erzeugung konkreter Objekte, die einen InterfaceTyp haben, beliebige Implementierungen dieses Interfaces nutzen.
Aufgabe 2 (Collections):
(3 Punkte)
In dieser Aufgabe sollen Sie nach Möglichkeit vordenierte Klassen aus dem
den, welches Sie im Package
java.util
Collections Framework verwenTerm und Variable aus
nden. Auÿerdem benötigen Sie die Klassen
Aufgabe 1.
Ergänzen Sie die Klasse
Term um eine Methode Term applySubstitution(Map<Variable,Term> substitution),
welche einen Term zurück liefert. Dieser Term entsteht aus dem ursprünglichen Term, indem alle Vorkommen
von Variablen in der übergebenen
Map
durch die ihnen zugeordneten Terme ersetzt wurden. Eine
Map
modelliert
also eine mathematische Abbildung als Menge von Paaren. Der ursprüngliche Term (genauer das Objekt, das den
ursprünglichen Term repräsentiert) soll dabei nicht modiziert werden.
f(X,a,Y,g(X,Z)) repräsentiert, bei
Map m lediglich die Einträge X → b und Y → c
t.applySubstitution(m) den Term f(b,a,c,g(b,Z)) zurück.
Nehmen wir zum Beispiel an, dass der
dem
X, Y
und
Z
Term t
den mathematischen Term
Variablen sind. Ferner nehmen wir an, dass die
enthält. Dann liefert der Aufruf
1
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
Sie können ausnutzen, dass die vorgegebene Datenstruktur für
Term
und
Variable
unveränderlich (immutable)
ist. Nutzen Sie die Möglichkeit, Methoden in Unterklassen zu überschreiben.
Hinweise:
•
Schauen Sie sich die API des
Collections
Frameworks an, um sich über das
Map
Interface zu informie-
ren. Wenn Sie konkrete Objekte erzeugen möchten, die einen Interface-Typ haben, dürfen Sie beliebige
Implementierungen der entsprechenden Interfaces verwenden.
•
Sie können die Klasse
TermTest.java von unserer Homepage benutzen, um Ihre Implementierung zu testen.
Tutoraufgabe 3 (Generics):
Wir wollen in dieser Aufgabe eine bestehende Datenstruktur um Generics erweitern. Laden Sie dazu die Datei
GenericTrees.zip
TreeSum.java.
von der Homepage herunter. Darin nden Sie die Klassen
Tree.java, TreeTest.java
und
Tree so ab, dass ein Typparameter der Klasse den Typ der gespeicherten Elemente festlegt und
int festgelegt ist. Passen Sie auch den Konstruktor und alle Methoden der Klasse an.
a) Ändern Sie
dieser nicht mehr auf
a) markierten Anweisungen in
TreeTest auskommentieren und das Programm ausführen. Der in TreeTest denierte Baum sollte als (1,
(23, (42, (), ()), ()), (65, (), ())) ausgegeben werden.
Sie können testen, ob Ihre Implementierung korrekt ist, indem Sie die mit
b) Passen Sie nun auch die Klasse
TreeSum
an, damit Sie mit der neuen Denition von
Sie soll dabei weiterhin nur mit Bäumen umgehen können, die
Integer
Sie können testen, ob Ihre Implementierung korrekt ist, indem Sie die mit
TreeTest
Tree
umgehen kann.
enthalten.
b)
markierten Anweisungen in
auskommentieren und das Programm ausführen. Die ausgegebene Summe der Elemente des
Baumes sollte
131
sein.
c) Denieren Sie ein Interface
TreePredicate, das einen generischen Parameter V hat und eine Methode isOK
Tree mit Werten vom Typ V bekommt und einen booleschen Wert zurückgibt.
zur Verfügung stellt, die einen
Comparable<T> ist in der Java-Standardbibliothek java.lang vordeniert. Klassen, die
Comparable<T> implementieren, müssen eine nicht-statische Methode int compareTo(T o) zum Vergleichen zur Verfügung stellen. Das heiÿt, dass wenn man o1.compareTo(o2) aufruft, der Rückgabewert -1
sein soll, wenn o1 kleiner als o2 ist, 0 wenn o1 gleich o2 ist und 1, wenn o1 gröÿer als o2 ist.
d) Das Interface
ComparePredicate<V>, die TreePredicate<V> implementiert. Der TyComparePredicate soll so eingeschränkt werden, dass er nur Klassen erlaubt, die
Implementieren Sie eine Klasse
V von
Comparable<V> implementieren.
pparameter
Die Klasse
ComparePredicate<V>
soll zwei Attribute
minEle
und
maxEle
vom Typ
V
haben. Der Kon-
struktor der Klasse soll zwei entsprechende Argumente bekommen und sie in diesen Attributen speichern.
Die Methode
value
isOK
soll nun so implementiert werden, dass
true
zurückgegeben wird, wenn der im Feld
gespeicherte Wert des übergebenen Baumelementes gröÿer als
Verwenden Sie die Methode
compareTo,
minEle
Sie können testen, ob Ihre Implementierung korrekt ist, indem Sie die mit
TreeTest
filterElements
23 und 42 sein.
und die Methode
gebenen Elemente sollten
und kleiner als
maxEle
ist.
um dies zu überprüfen.
d)
markierten Anweisungen in
auskommentieren und das Programm ausführen. Die ausge-
IntTree, die Tree so erweitert, dass nur Integer-Elemente gespeiIntTree das Interface Comparable so implementieren, dass IntTree-Objekte
werden können, indem in compareTo die Summe Ihrer Elemente verglichen wird.
e) Implementieren Sie nun eine Klasse
chert werden. Auÿerdem soll
miteinander verglichen
Sie können testen, ob Ihre Implementierung korrekt ist, indem Sie die mit
TreeTest auskommentieren und das Programm ausführen.
(23, (), ())), (65, (104, (), ()), ())) sein.
2
e)
markierten Anweisungen in
Der ausgegebene Baum sollte
(12, (17, (),
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
Aufgabe 4 (Generics und Collections): (1,5 + 1 + 3 + 1 + 1 + 1 + 4 + 1 + 2 + 0,5 = 16
Punkte)
Um den Umgang mit generischen Datentypen zu üben, entwerfen wir in dieser Aufgabe eine einfache Datenstruktur
für Graphen.
Ein Graph besteht aus beliebig vielen Knoten und Kanten, wobei jede Kante zwei Knoten verbindet. In dieser
Aufgabe hat jeder Knoten einen Wert, auÿerdem hat jede Kante eine Beschriftung.
Laden Sie die Datei
Generics.zip von der Vorlesungs-Homepage herunter. Darin nden Sie eine unvollständige
Edge.java, einen vorgefertigen Test (als .class-Datei) und das enum Color.
Kanten-Implementierung
a) Als Einstimmung auf den Umgang mit Generics entwerfen wir in dieser Teilaufgabe ein allgemeines Prädikat.
Ein konkretes Prädikat für bestimmte Arten von Eingaben kann für jede solche Eingabe entscheiden, ob
diese OK ist oder nicht. Beispielsweise könnte ein Prädikat, das auf Zahlen arbeitet, nur positive Zahlen
akzeptieren. Ein Prädikat, das Aussagen über Menschen treen kann, könnte beispielsweise nur schöne
blauäugige Blondinen akzeptieren.
Predicate mit einem generischen Typ-Parameter. Geben Sie in diesem
Predicate eine Methode isOK hat. Die Methode isOK soll ein
Objekt vom Typ des generischen Parameters als Eingabe bekommen und als Rückgabe einen boolean-Wert
Entwerfen Sie ein Interface namens
Interface vor, dass jede Implementierung von
liefern.
Schreiben Sie anschlieÿend eine Prädikatklasse
mentieren Sie die Methode
isOK
NotRed als Implementierung von Predicate<Color>. ImpleColor.RED der Wert true zurückgegeben
so, dass für alle Farben auÿer
wird.
Implementieren Sie das Interface
Parameter. Die Methode
isOK
Predicate auch durch die Klasse PredicateTrue mit einem generischem
true zurückgeben. Verwenden Sie hierfür den (einzigen)
soll nun immer
generischen Parameter, um den Typ der zu überprüfenden Objekte festzulegen.
b) Die (heruntergeladene) Klasse
Edge
wird benutzt, um einzelne Kanten im Graphen zu repräsentieren. Jede
Kante hat eine Beschriftung sowie einen Zielknoten (am Ende der Kante).
Die aktuelle Implementierung ist allerdings noch nicht generisch, weshalb nur Kanten repräsentiert werden
können, die einen Integer-Wert als Kantenbeschriftung haben.
Ergänzen Sie die Klasse um einen generischen Parametern, so dass der Typ der Kantenbeschriftung beliebig
ist. Passen Sie hierfür die gesamte Klasse an.
c) Schreiben Sie nun eine Klasse
Node
zur Darstellung von Knoten im Graphen. Um einen Graphen mit den
vorhandenen Verbindungen darzustellen, speichern wir pro Knoten eine Menge von ausgehenden Kanten.
Die Klasse
Node soll zwei generische Parameter haben. Ein Parameter gibt den Typen der Knotenwerte an,
der andere den Typen der Kantenbeschriftungen.
Deklarieren bzw. implementieren Sie in der Klasse
Node
•
ein Attribut, in dem der (generische) Wert des Knotens gespeichert wird
•
ein Attribut, das die ausgehenden Kanten (vom Typ
•
einen Konstruktor, der eine Knotenbeschriftung als Argument übergeben bekommt und diese im ent-
Edge)
speichert
sprechenden Attribut speichert. Der Konstruktor initialisiert das Attribut der ausgehenden Kanten so,
dass der neu erzeugte Knoten keine ausgehende Kante hat.
Als Datenstruktur für die ausgehenden Kanten bietet sich hier der Datentyp
Set
aus dem Collections-
Framework von Java an. Als konkrete Implementierung können Sie die mit Java mitgelieferte Implementierung
LinkedHashSet
benutzen. Die Dokumentation dieser Datenstrukturen nden Sie in der Java API.
Edge ist der Verweis auf den Zielknoten mittels private Node target noch nicht generisch.
Edge um einen zweiten generischen Parameter, der für den Typ der Knotenwerte
benutzt wird und passen Sie die Klasse entsprechend an. Passen Sie auch die Klasse Node an, so dass diese
beide generischen Parameter der Klasse Edge benutzt.
d) In der Klasse
Ergänzen Sie die Klasse
3
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
e) Implementieren Sie in der Klasse
Node die nicht-statische Methode addOut. Diese Methode soll eine weitere
ausgehende Kante (zu einem Knoten) in das Attribut des aktuellen Knotens hinzufügen.
addOut ist ein Knoten, der den Zielknoten der neuen ausgehenden Kante
Das erste Argument der Methode
darstellt. Das zweite Argument ist die Beschriftung der neuen Kante.
Erzeugen Sie aus diesen Informationen ein neues
Edge-Objekt
und fügen Sie dieses in das Attribut für die
ausgehenden Kanten hinzu.
f ) Ähnlich zur Methode
addOut
soll
Node
auch eine Methode
addEdge
zur Verfügung stellen. Diese erstellt
zwischen zwei gegebenen Knoten eine neue Kante (mit gegebener Beschriftung). Da diese Methode unabhängig vom aktuellen Knoten arbeitet (also beim Aufruf eine Kante zwischen zwei anderen Knoten erstellt
werden könnte), ist die Methode statisch.
Implementieren Sie die Methode, unter Zuhilfenahme von
addOut,
so dass das erste Argument der Start-
knoten der neuen Kante ist, das zweite Argument der Zielknoten und das dritte Argument die Kantenbeschriftung.
g) Eine bei Graphen interessante Frage ist, welche Knoten ausgehend von einem bestimmten Knoten erreichbar
sind. Ein Knoten ist dann erreichbar, wenn man durch Entlanglaufen beliebig vieler Kanten zu diesem Knoten
gelangen kann.
Schreiben Sie die nicht-statische Methode
Knoten erreichbaren Knoten in einem
Set
getReachableNodes
in der Klasse
Node,
die alle vom aktuellen
zurückgibt.
Um diese Menge zu berechnen, empehlt sich die Verwendung einer rekursiven Hilfsmethode. Übergeben
Sie dieser Hilfsmethode die (anfangs leere) Ergebnismenge und fügen Sie nach und nach alle erreichbaren
Knoten hinzu. Fügen Sie hierfür zuerst den aktuellen Knoten zu der Menge hinzu und rufen Sie anschlieÿend
die Methode rekursiv auf allen direkten Nachfolgern auf.
Da ein Graph auch zyklisch sein kann, terminiert dieser naive Algorithmus dann nicht. Passen Sie Ihre
Implementierung so an, dass die Methode auch auf zyklischen Graphen terminiert und das korrekte Ergebnis
zurückgegeben wird.
Überprüfen Sie hierfür, ob Sie den aktuellen Knoten schon einmal besucht haben, indem Sie nach einem
Vorkommen in der Menge suchen. Nutzen Sie hierfür die vom Interface
Set
zur Verfügung gestellte Funk-
tionalität.
h) Erweitern Sie
getReachableNodes um ein Eingabeargument, in dem ein Prädikat für Kantenbeschriftungen
übergeben wird. Passen Sie Ihre Implementierung so an, dass für die Berechnung der erreichbaren Knoten
nur die Kanten durchlaufen werden, bei deren Beschriftungen die Überprüfung mittels
true
isOK
des Prädikats
zurückgibt.
Sie dürfen davon ausgehen, dass das Prädikat nicht
null
ist.
getContents in der Klasse Node, die für alle erreichbaren Knoten
Set zurückgibt. Die Methode getContents soll hier einen Kantenlter übergeben
i) Schreiben Sie eine nicht-statische Methode
die Knoteninhalte in einem
bekommen, der bei der Berechnung der erreichbaren Knoten benutzt wird.
Sie dürfen davon ausgehen, dass das Prädikat nicht
j) Stellen Sie auÿerdem eine Methode
getContents
null
ist.
zurück, die kein Argument hat. Diese Methode soll die
Beschriftungen aller erreichbaren Knoten zurückgeben. Verwenden Sie hierfür die Implementierung von
getContents mit Prädikat aus der vorherigen Teilaufgabe, indem Sie ein Prädikat der Klasse PredicateTrue
benutzen.
Testen Sie Ihre Implementierung mit der mitgelieferten
Test-Klasse. Der Aufruf der main-Methode sollte folgende
Ausgabe geben:
Erzeuge
Erzeuge
Erzeuge
Erzeuge
neuen
neuen
neuen
neuen
Knoten
Knoten
Knoten
Knoten
mit
mit
mit
mit
String
String
String
String
"a"
"b"
"c"
"d"
als
als
als
als
Wert
Wert
Wert
Wert
4
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
Erzeuge neuen Knoten mit String "e" als Wert
Verbinde a-Knoten mit b-Knoten durch Kante mit Beschriftung Color.GREEN
Verbinde b-Knoten mit c-Knoten durch Kante mit Beschriftung Color.BLUE
Verbinde c-Knoten mit d-Knoten durch Kante mit Beschriftung Color.RED
Verbinde c-Knoten mit e-Knoten durch Kante mit Beschriftung Color.GREEN
Verbinde e-Knoten mit c-Knoten durch Kante mit Beschriftung Color.GREEN (mit statischer Methode)
Erzeuge NotRed-Praedikat
Erreichbare Inhalte von a-Knoten: [a, b, c, d, e]
Ueber nicht-rote Kanten von a-Knoten erreichbare Inhalte: [a, b, c, e]
Tutoraufgabe 5 (Listen in Haskell):
Seien
x, y, z
ganze Zahlen vom Typ
Int.
und
xs
und
ys
Listen der Längen
n
und
m
vom Typ
[int]
Welche der folgenden Gleichungen zwischen Listen sind richtig und welche nicht? Begründen Sie Ihre Antwort.
Falls es sich um syntaktisch korrekte Ausdrücke handelt, geben Sie für jede linke und rechte Seite auch an, wie
viele Elemente in der jeweiligen Liste enthalten sind und welchen Typ sie hat.
Beispiel : Die Liste [[1,2,3],[1,4]] hat den Typ [[Int]] und enthält 2 Elemente.
(i)
(ii)
x:[] = [x]
(x,y):xs = x:y:xs
(iii)
(x:([y] ++ xs)) ++ ys = ([x] ++ (y:xs)) ++ ys
(iv)
x:[xs] = [x:xs]
(v)
(x:[y,z]):[] = [[x] ++ (y:[z])]
Hinweise:
•
Hierbei steht
++
für den Verkettungsoperator für Listen. Das Resultat von
entsteht, wenn die Elemente aus
ys
ys
in der Reihenfolge wie sie in
xs ++ ys
ist die Liste, die
stehen an das Ende von
xs
angefügt werden.
Beispiel : [1,2]
•
++ [1,2,3] = [1,2,1,2,3]
Falls linke und rechte Seite gleich sind, genügt eine Angabe des Typs und der Elementzahl
Aufgabe 6 (Listen in Haskell):
Seien
x, y, z
ganze Zahlen vom Typ
Int.
(5 Punkte)
und
xs
und
ys
Listen der Längen
n
und
m
vom Typ
[int]
Welche der folgenden Gleichungen zwischen Listen sind richtig und welche nicht? Begründen Sie Ihre Antwort.
Falls es sich um syntaktisch korrekte Ausdrücke handelt, geben Sie für jede linke und rechte Seite auch an, wie
viele Elemente in der jeweiligen Liste enthalten sind und welchen Typ sie hat.
Beispiel : Die Liste [[1,2,3],[1,4]] hat den Typ [[Int]] und enthält 2 Elemente.
(i)
x:xs = [x] ++ xs
(ii)
(x:y):xs = x:y:xs
(iii)
[x,y,xs] = x:y:xs
(iv)
x:y:(x:[x] ++ xs) = [x,y,x] ++ (x:xs)
(v)
[]:[[],[[1]]] = [[],[]]:[[[1]]]
5
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
Hinweise:
•
Falls linke und rechte Seite gleich sind, genügt eine Angabe des Typs und der Elementzahl.
•
Obwohl Ihnen ein Haskell Compiler hier sehr hilfreich sein kann, sollten Sie diese Aufgabe von Hand lösen
um einen Übungseekt zu erzielen.
•
Gehen Sie davon aus, dass die Zahl
1
den Typ
Int
hat.
Tutoraufgabe 7 (Programmieren mit Haskell):
Implementieren Sie alle der im folgenden beschriebenen Funktionen in Haskell. Geben Sie dabei die entsprechenden
Typdeklarationen an. Verwenden Sie auÿer Listenkonstruktoren (und deren Kurzschreibweise) und Vergleichsoperatoren wie
<=, ==,. . . keine
vordenierten Funktionen (dies schlieÿt auch arithmetische Operatoren ein), auÿer
denen, die in den jeweiligen Teilaufgaben explizit erlaubt werden.
a)
stunden w d h
Gibt die Anzahl der Stunden zurück, die in
stunden 5 4 3 den Wert 939.
dürfen hier + und * verwenden.
Beispiel
Sie
b)
mult x y
Berechnet
w Wochen, d Tagen und h Stunden vergehen. So berechnet zum
Die Funktion darf sich auf negativen Eingaben beliebig verhalten.
x · y. Sie dürfen dazu + und - verwenden. Die Funktion darf sich auf negativen Eingaben beliebig
verhalten.
c)
bLog x
x. Somit liefert bLog 1 den Wert 1, bLog 5 den
Berechnet den aufgerundeten Logarithmus zur Basis 2 von
Wert
d)
3
und
bLog 32
den Wert
5.
Sie dürfen hier
+
und
getLastTwo xs
Berechnet die Teilliste der letzten zwei Elemente der
[12, 7, 23]
e)
den Wert
schachtel xs
Berechnet für eine
[7, 23].
Int-Liste
appendEnd x ys
Berechnet die Int-Liste,
Beispielsweise berechnet
verwenden. Falls
g)
x
i)
j)
Beispielsweise berechnet
Int-Listen, die jedes Element in einer eigenen
schachtel [1, 5, 2] den Wert [[1],[5],[2]].
die entsteht, wenn man die Zahl
appendEnd 3 [12, 7, 23]
getLastTwo
Teilliste enthält.
x x-mal an das Ende der Int-Liste ys anfügt.
[12, 7, 23, 3, 3, 3]. Sie dürfen hier -
die Liste
negativ ist, darf sich Ihre Funktion beliebig verhalten.
Berechnet das kleinste Element, das in der
h)
Int-Liste xs.
Die Funktion darf sich auf Listen der Länge 0 und 1 beliebig verhalten.
kleinstes xs
[42, 7, 23]
verwenden.
eine Liste von
Zum Beispiel liefert der Aufruf
f)
*
den Wert
7.
Int-Liste xs vorkommt. Zum Beispiel liefert der Aufruf kleinstes
loesche x ys
Berechnet die Int-Liste, die entsteht, wenn man das erste Vorkommen von x aus der Int-Liste ys entfernt.
Zum Beispiel liefert der Aufruf loesche 5 [1,3,5,5,7] den Wert [1,3,5,7].
minSort xs
Sortiert die Int-Liste xs aufsteigend. Verwenden Sie dabei die Funktionen kleinstes
Aufruf minSort [5,3,1,8] liefert dann beispielweise den Wert [1,3,5,8].
prodList xs ys
Berechnet die Liste der Produkte der korrespondierenden Elemente der beiden
heiÿt, dass das Ergebnis zuerst das Produkt des ersten Elements von
6
xs
und
loesche.
Int-Listen xs
und
ys.
Der
Das
und des ersten Element von
ys
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
enthält, dann das Produkt der zweiten Elemente, u.s.w. Wenn die Listen unterschiedlich lang sind, soll die
Ergebnisliste nur so lang wie die kürzere der beiden Eingabelisten sein. Beispielsweise berechnet
[2,1,4,5] [6,2,7]
die Liste
[12,2,28].
Sie dürfen hier
*
prodList
verwenden.
Aufgabe 8 (Programmieren mit Haskell): (1 + 1 + 1 + 1 + 1 + 2 + 2 + 1 = 10 Punkte)
Implementieren Sie alle der im folgenden beschriebenen Funktionen in Haskell. Geben Sie dabei die entsprechenden Typdeklarationen an (wobei alle vorkommenden Listen den Typ
[Int haben sollen). Verwenden Sie auÿer
<= und - (Minus) keine vordenierten
Listenkonstruktoren (und deren Kurzschreibweise) und den Funktionen
Funktionen, auÿer denen, die in den jeweiligen Teilaufgaben explizit erlaubt werden.
a)
anhaengen xs ys
xs zurück, an die die Elemente der Liste ys angehängt wurden. Die Funktion
++. Ein Aufruf anhaengen [1,2] [3,4] liefert das Ergebnis [1,2,3,4].
Gibt die Liste der Elemente von
entspricht also der Funktion
b)
umdrehen xs
Gibt eine Variante der Liste
umdrehen [1,2,3]
c)
mischen xs
Die Funktion
xs
zurück, bei der die Reihenfolge der Elemente umgedreht wurde. Ein Aufruf
liefert als Ergebnis
mischen
[3,2,1].
Verwenden Sie hierbei die Funktion
soll eine Liste mischen, indem abwechselnd das erste und letzte Element der ver-
bleibenden Liste an die Ergebnisliste angehängt werden. So liefert ein Aufruf
Ergebnis
d)
anhaengen.
[1,5,2,4,3].
Verwenden Sie hierbei die Funktionen
anhaengen
und
mischen [1,2,3,4,5]
umdrehen.
das
first n xs
n und eine Liste xs übergeben und liefert die ersten n Elemente
n kleiner als die Länge der Liste xs ist, darf sich ihr Programm beliebig verhalten.
first 2 [1,2,3] liefert als Ergebnis [1,2].
Die Funktion bekommt eine natürliche Zahl
der Liste zurück. Falls
Ein Aufruf
e)
teilListe xs n l
xs und zwei natürliche Zahlen n und l übergeben. Nun soll eine Teilliste
xs der Länge l ab dem n-ten Element der Liste zurückgegeben werden. Die Elemente einer Liste werden
von 0 an nummeriert. Verwenden Sie hierbei die Funktion first. Ein Aufruf teilListe 1 2 [1,2,3,4]
liefert also [2,3] als Ergebnis. Falls der Index n nicht in der Liste enthalten ist oder die Länge l über das
Die Funktion bekommt eine Liste
von
Ende der Liste hinausragt, darf sich ihre Funktion beliebig verhalten.
f)
merge xs ys
Die Funktion bekommt zwei
aufsteigend sortierte Listen xs und ys als Argumente und gibt eine aufsteigend
xs und ys enhält. Ein Aufruf merge [1,3,5] [2,4,4,8]
merge [] [1,2,3,4] liefert hingegen [1,2,3,4].
sortierte Liste zurück, die alle Elemente von
liefert somit
[1,2,3,4,4,5,8].
Ein Aufruf
Hinweise:
•
g)
Vergleichen Sie Listenelemente mit der Funktion
split xs
Die Funktion bekommt eine Liste
die Elemente der Liste
Liste
xs
xs
<=.
xs als Argument und gibt ein Tupel von zwei Listen zurück. Hierbei werden
abwechselnd auf die beiden Ergebnislisten verteilt, so dass das erste Element der
xs das erste Element
([1,3,5],[2,4]).
das erste Element der ersten Ergebnisliste ist und das zweite Element der
der zweiten Ergebnisliste ist. Ein Aufruf
split [1,2,3,4,5]
liefert das Ergebnis
Hinweise:
xs
•
Konstruieren Sie 3 Fälle: Die Liste
•
Im dritten Fall hilft es, erst den Rest der Liste (ohne die ersten zwei Elemente) aufzuteilen.
hat kein, ein oder mindestens zwei Elemente.
7
Programmierung WS11/12
Übungsblatt 10 (Abgabe 19.01.2012)
h)
sort xs
Die Funktion bekommt eine Liste
xs
und gibt ihre Elemente in aufsteigend sortierter Reihenfolge aus.
Listen der Länge höchstens eins sind schon sortiert. Ansonsten soll die Liste mit der Funktion
kleinere Listen zerteilt werden, diese dann rekursiv sortiert und mit der Funktion
Liste zusammengefasst werden.
8
merge
split in zwei
zu einer sortierten
Herunterladen