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