Tutoraufgabe 1 (Collections):

Werbung
Programmierung WS14/15
C. Aschermann, F. Frohn, J. Hensel, T. Ströder
Übungsblatt 9 (Abgabe 07.01.2015)
Prof.aaDr. J. Giesl
Allgemeine Hinweise:
ˆ Die
sollen in Gruppen von je
aus der
bearbeitet werden.
der Studierenden sind auf jedes Blatt
der Abgabe zu schreiben.
ˆ Die
muss
auf das
der Abgabe geschrieben
werden. Notieren Sie die Gruppennummer gut sichtbar, damit wir besser sortieren können.
ˆ Die Lösungen müssen
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 auch vor der Abgabefrist direkt bei Ihrer Tutorin/Ihrem
Tutor abgeben.
ˆ In einigen Aufgaben müssen Sie in Java oder Haskell programmieren und .java- bzw. .hs-Dateien anlegen.
Sie diese aus schicken Sie sie per
vor Mittwoch, dem 07.01.2015 um 15:00
Uhr an Ihre Tutorin/Ihren Tutor.
Stellen Sie sicher, dass Ihr Programm von javac
GHC
wird, ansonsten werden keine
Punkte vergeben.
ˆ Aufgaben, die mit einem markiert sind, sind Sonderaufgaben mit erhöhtem Schwierigkeitsgrad. Sie
tragen nicht zur Summe der erreichbaren Punkte bei, die für die Klausurzulassung relevant ist, jedoch
werden Ihnen die in solchen Aufgaben erreichten Punkte ganz normal gutgeschrieben.
ˆ Die Aufgaben, die Java betreen, zählen bzgl. der Zulassungsbedingungen zur ersten Hälfte, während
die Aufgaben, die Haskell betreen, bereits zur zweiten Hälfte zählen.
Hausaufgaben
2 Studierenden
(Tutorium)
gleichen Kleingruppenübung
Namen und Matrikelnummern
Heften bzw. tackern Sie die Blätter!
Nummer der Übungsgruppe
links oben
erste Blatt
bis Mittwoch, den 07.01.2015 um 15:00 Uhr
Drucken
und
E-Mail
bzw.
akzeptiert
∗
Tutoraufgabe 1 (Collections):
In dieser Aufgabe geht es um die Implementierung einer Datenstruktur für Mengen, welche in das bestehende Collections Framework eingebettet werden soll. Sie benötigen dafür die Klassen FunctionalSet,
SimpleFunctionalSet, EmptySet, AddSet und RemoveSet, welche Sie als .java Dateien von unserer Webseite
herunterladen können.
Die in dieser Aufgabe zu betrachtende Mengenstruktur basiert auf einer Liste von Einfüge- (Add) und Löschoperationen (Remove) mit jeweils einem Element, die vom Ausgangspunkt einer leeren Menge (Empty) angewendet
werden. Zum Beispiel lässt sich die Menge {1, 2, 3} als die Liste Add 3, Add 2, Add 1, Empty darstellen.
Will man nun das Element 2 aus der Menge löschen, so entfernt man nicht das zweite Element aus der Liste,
sondern fügt ein weiteres Remove Element hinzu und erhält Remove 2, Add 3, Add 2, Add 1, Empty. Auf
diese Weise erhält man eine Datenstruktur, bei der niemals Objekte entfernt werden (mit Ausnahme der clear
Methode, welche die Liste wieder auf Empty setzen soll). Eine solche Mengendarstellung nennt man auch funktional, da die Einfüge- und Löschoperationen als Funktionen aufgefasst werden können, welche auf die leere
Menge angewendet werden.
Die vorgegebene Klasse FunctionalSet implementiert bereits das Set Interface bis auf die iterator Methode. Implementieren Sie diese Methode. Implementieren Sie dazu eine weitere generische Klasse
FunctionalSetIterator<E>, welche das Interface Iterator<E> aus dem Package java.util implementiert.
Schlagen Sie für die zu implementierenden Methoden hasNext, next und remove die Funktionalitäten in der
Java API für das Interface Iterator nach (die remove Operation soll durch Ihren Iterator unterstützt werden).
Dies betrit insbesondere auch die durch diese Methoden zu werfenden Exceptions.
Sie können die main Methode der Klasse FunctionalSet nutzen, um Ihre Implementierung zu testen.
1
Programmierung WS14/15
Übungsblatt 9 (Abgabe 07.01.2015)
(9 + 3 + 2 + 3∗ = 14 + 3∗ Punkte)
Aufgabe 2 (Collections):
In dieser Aufgabe geht es ebenfalls um die Implementierung einer Datenstruktur für Mengen, welche in das
bestehende Collections Framework eingebettet werden soll. Sie benötigen dafür die Klassen TrieSet und
TrieNode, welche Sie als .java Dateien von unserer Webseite herunterladen können.
Die in dieser Aufgabe zu betrachtende Mengenstruktur basiert auf einer Suchbaumstruktur zur Indizierung der
Elemente. Die hier verwendeten Suchbäume werden genannt (von retrieval). Jedem Element der Menge
wird ein Schlüssel als String zugeordnet. Die Knoten des Tries enthalten nun Teil-Strings, anhand derer die
Suche durch den Baum nach einem Element gesteuert wird. Die Konkatenation der Teil-Strings entlang der
besuchten Knoten im Baum ergibt den Schlüssel des gesuchten Elements. Die Wurzel enthält dabei immer den
leeren String, da dieser ein Präx für jeden String ist. Folgender Trie speichert beispielsweise vier Elemente
mit den Schlüsseln Bahn, Bahnfahrt, Bahnhof und Zug:
foo
Tries
Bahn
Zug
Bahn
Zug
hof
fahrt
Bahnhof
Bahnfahrt
In diesem Beispiel ist jedes Element identisch zu seinem Schlüssel. Dies muss im Allgemeinen nicht so sein.
Insbesondere kann ein Knoten in einem Trie auch mehrere verschiedene Elemente speichern, wenn deren
Schlüssel identisch sind. Allerdings werden gleiche Elemente nicht mehrfach gespeichert, da es sich ja um eine
Mengenstruktur handelt. Jeder Knoten enthält daher ein Attribut elements vom Typ Set.
Die vorgegebene Klasse TrieSet implementiert bereits das Set Interface bis auf die Methoden iterator,
retainAll und add (letztere ist eigentlich in TrieSet vollständig implementiert, aber die von ihr aufgerufene
add Methode in der Klasse TrieNode ist es nicht).
Sie können die main Methode der Klasse TrieSet nutzen, um Ihre Implementierungen der folgenden Aufgabenteile zu testen. Dabei können Sie auch Teile des Tests auskommentieren, falls Sie nur Teile der Aufgaben
bearbeitet haben.
Implementieren Sie die Methode iterator in der Klasse TrieSet. Implementieren Sie dazu eine generische Klasse TrieIterator<E>, welche das Interface Iterator<E> aus dem Package java.util implementiert. Schlagen Sie für die zu implementierenden Methoden hasNext, next und remove die Funktionalitäten in der Java API für das Interface Iterator nach (die remove Operation soll durch Ihren
Iterator unterstützt werden). Dies betrit insbesondere auch die durch diese Methoden zu werfenden
Exceptions. Die Klasse TrieIterator muss im gleichen Package wie TrieNode implementiert werden,
damit Sie auf die Getter-Methoden der Klasse TrieNode zugreifen können.
Hinweise:
ˆ Denken Sie daran, dass die Set Attribute an den jeweiligen Knoten bereits implementierte Iteratoren
anbieten.
ˆ Sie nden Dokumentationen zu weiteren Klassen aus dem Collections Framework (wie z.B. TreeMap)
ebenfalls in der Java API.
Implementieren Sie die Methode retainAll in der Klasse TrieSet. Schlagen Sie deren Funktionalität
ebenfalls in der Java API nach. Benutzen Sie zur Implementierung dieser Methode nicht die add oder
remove Methoden der Klassen TrieSet und TrieNode. Sie dürfen jedoch die remove Methode des Iterators aus der vorigen Teilaufgabe nutzen.
Überschreiben Sie die Methode public String toString() in der Klasse TrieSet, sodass diese einen
String zurückliefert, der mit einer önenden geschweiften Klammer beginnt, dann die Elemente der
Menge durch Kommata getrennt aufzählt und schlieÿlich mit einer schlieÿenden geschweiften Klammer
a)
b)
c)
2
Programmierung WS14/15
Übungsblatt 9 (Abgabe 07.01.2015)
∗
d)
endet. Wenn ein TrieSet also beispielsweise die Elemente 1, 2 und 3 enthält, soll der von toString
zurückgelieferte String "{1, 2, 3}" sein.
Implementieren Sie die Methode add in der Klasse TrieNode, sodass die vorgegebene Implementierung
der add Methode in der Klasse TrieSet korrekt bzgl. der Spezikation im Set Interface ist. Achten
Sie darauf, dass es zu keiner Zeit einen Knoten im Trie geben darf, der verschiedene Kindknoten hat,
deren Teil-Strings aber ein gemeinsames nicht-leeres Präx haben. Sie nden nützliche Methoden zur
Verarbeitung von Strings in der zugehörigen Java API.
Aufgabe 3 (Klassenhierarchie∗ ):
(3∗ + 3∗ + 3∗ + 3∗ = 12∗ Punkte)
In dieser Aufgabe wird eine Software zum Verwalten von beliebig vielen Serverfarmen betrachtet.
(1) Eine Serverfarm enthält beliebig viele Rechner.
(2) Jeder Rechner hat eine eindeutige MAC-Adresse (repräsentiert durch einen String), welche für die IPVergabe verwendet wird.
(3) Die meisten Rechner in einer Serverfarm sind Server.
(4) Einige Rechner sind jedoch Terminals zur Kontrolle der Server.
(5) Alle fernwartbaren Rechner können neu gestartet werden.
(6) Alle fernwartbaren Rechner stellen eine Funktion bereit, die angibt, ob der Rechner abgestürzt ist.
(7) Eine Serverfarm stellt die Funktionalität bereit, alle ihre abgestürzten, fernwartbaren Rechner neu zu
starten.
(8) Server und Terminals sind immer fernwartbar. Wie die Fernwartung implementiert ist, hängt von der
Rechnerart ab.
(9) Bei Servern ist vor allem die Anzahl der CPUs und die zur Verfügung stehende Menge an RAM interessant.
(10) Servicetechniker haben kleine Diagnoserechner, welche nicht fernwartbar sind.
(11) Datenbankserver sind Server, bei denen vor allem das Volumen der Festplatte relevant ist.
(12) Es gibt keine sonstigen Rechner.
Entwerfen Sie unter Berücksichtigung der Prinzipien der Datenkapselung eine geeignete Klassenhierarchie
für die Serverfarm. Notieren Sie keine Konstruktoren, Getter und Setter. Sie müssen nicht markieren, ob
Attribute nal sein sollen. Achten Sie darauf, dass gemeinsame Merkmale in Oberklassen bzw. Interfaces
zusammengefasst werden. Verwenden Sie hierbei die Notation aus Aufgabe 3, Blatt 7. Welche Objekte
realisieren Sie als Klasse und welche als Interface? Begründen Sie ihre Antwort.
Implementieren Sie die in Punkt (6) beschriebene Funktion so, dass sie mit einer Wahrscheinlichkeit
von 50% true zurückgibt. Hierzu können Sie die aus Aufgabe 2, Übungsblatt 8 bekannte Klasse Zufall
benutzen. Implementieren Sie auÿerdem die Funktion void abgestuerzteNeustarten() in der Klasse
ServerFarm, welche alle abgestürzten, fernwartbaren Rechner einer Serverfarm neu startet.
Stellen Sie sicher, dass alle Klassen über sinnvolle Konstruktoren verfügen. Bedenken Sie dabei, dass
jeweils auch der Konstruktor der Oberklasse aufgerufen werden soll. Die MAC-Adresse eines Rechners soll
mit einem zufälligen String der Länge 12 initialisiert werden, der aus den Zeichen abcdef0123456789
besteht.
a)
b)
c)
3
Programmierung WS14/15
Übungsblatt 9 (Abgabe 07.01.2015)
d)
Erstellen Sie eine Klasse IpVerwaltung, welche Rechnern IP-Adressen zuweist. Gehen Sie dafür davon
aus, dass IP-Adressen Integer zwischen 167968768 und 168034303 sind. Implementieren Sie in dieser
Klasse eine Funktion int ipZuweisen(Rechner r), welche dem Rechner r eine IP-Adresse zuweist und
diese zurückgibt. Dabei soll sich die Klasse IpVerwaltung merken, welche IP-Adresse zu welcher MACAdresse gehört. Falls die Methode ipZuweisen zweimal mit dem gleichen Rechner als Argument aufgerufen wird, soll beide Male
IP-Adresse zurückgeliefert werden. Verwenden Sie die Klasse HashMap
(siehe http://www.java-tutorial.org/maps.html bzw. https://docs.oracle.com/javase/8/docs/
api/java/util/HashMap.html), um die Zuordnung zwischen MAC- und IP-Adressen zu verwalten.
die gleiche
Tutoraufgabe 4 (Auswertungsstrategie):
Gegeben sei das folgende Haskell-Programm:
listProd :: [ Int ] -> Int
listProd [] = 1
listProd ( x : xs ) = x * listProd xs
everySecond
everySecond
everySecond
everySecond
:: [ Int ] -> [ Int ]
[] = []
[x] = [x]
( x : _ : xs ) = x : everySecond xs
minus10 :: [ Int ] -> [ Int ]
minus10 [] = []
minus10 ( x : xs ) = x - 10 : minus10 xs
Die Funktion listProd multipliziert die Elemente einer Liste. Beispielsweise ergibt listProd [3,5,2,1] die
Zahl 30. Die Funktion everySecond bekommt eine Liste als Eingabe und gibt die gleiche Liste zurück, wobei
jedes zweite Element gelöscht wurde. So ergibt everySecond [1,2,3] die Liste [1,3]. Die Funktion minus10
gibt seine Eingabeliste zurück, wobei von jedem Element 10 subtrahiert wurde.
Geben Sie alle Zwischenschritte bei der Auswertung des Ausdrucks
listProd (everySecond (minus10 [3,2,1]))
an. Schreiben Sie hierbei (um Platz zu sparen) p, s und m statt listProd, everySecond und minus10.
Hinweise:
ˆ Beachten Sie, dass Haskell eine Leftmost-Outermost Auswertungsstrategie besitzt. Allerdings sind Operatoren wie * und +, die auf eingebauten Zahlen arbeiten, strikt, d.h. hier müssen vor Anwendung des
Operators seine Argumente vollständig ausgewertet worden sein (wobei zunächst das linke Argument
ausgewertet wird).
4
Programmierung WS14/15
Übungsblatt 9 (Abgabe 07.01.2015)
Aufgabe 5 (Auswertungsstrategie):
(5 Punkte)
Gegeben sei das folgende Haskell-Programm:
isEmpty :: [ a ] -> Int
isEmpty [] = 1
isEmpty _ = 0
removePairs :: [ Int ] -> [ Int ]
removePairs ( x : y : xs ) | x == y
= removePairs xs
| otherwise = x : ( removePairs ( y : xs ))
removePairs x
= x
listSum :: [ Int ] -> Int
listSum []
= 0
listSum ( x : xs ) = x + ( listSum xs )
Die Funktion isEmpty gibt zu einer Eingabeliste den Wert 1 zurück, falls die Liste leer ist. Sonst gibt sie 0
zurück. Die Funktion removePairs bekommt eine Liste als Eingabe und gibt die gleiche Liste zurück, wobei
von links nach rechts jeweils Paare von zwei aufeinander folgenden gleichen Elementen gelöscht wurden. So
ergibt removePairs [1,2,2,2,3,3,2] die Liste [1,2,2]. Die Funktion listSum addiert die Elemente einer
Liste. Beispielsweise ergibt listSum [3,5,2,1] die Zahl 11.
Geben Sie alle Zwischenschritte bei der Auswertung des Ausdrucks
listSum [isEmpty (removePairs [1,1]), isEmpty (removePairs [1,2,2,1])]
an. Schreiben Sie hierbei (um Platz zu sparen) e, r und s statt isEmpty, removePairs und listSum.
Hinweise:
ˆ Beachten Sie, dass Haskell eine Leftmost-Outermost Auswertungsstrategie besitzt. Allerdings sind Operatoren wie * und +, die auf eingebauten Zahlen arbeiten, strikt, d.h. hier müssen vor Anwendung des
Operators seine Argumente vollständig ausgewertet worden sein (wobei zunächst das linke Argument
ausgewertet wird).
Tutoraufgabe 6 (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.
: Die Liste [[1,2,3],[4,5]] hat den Typ [[Int]] und enthält 2 Elemente.
Hinweise:
ˆ Hierbei steht ++ für den Verkettungsoperator für Listen. Das Resultat von xs ++ ys ist die Liste, die
entsteht, wenn die Elemente aus ys in der Reihenfolge wie sie in ys stehen an das Ende von xs
angefügt werden.
: [1,2] ++ [1,2,3] = [1,2,1,2,3]
ˆ Falls linke und rechte Seite gleich sind, genügt
Angabe des Typs und der Elementzahl.
Beispiel
Beispiel
eine
a)
[] ++ [xs] = [] : [xs]
b)
[[]] ++ [x] = [] : [x]
c)
[x] ++ [y] = x : [y]
d)
x:y:z:(xs ++ ys) = [x,y,z] ++ xs ++ ys
e)
[(x:xs):[ys],[[]]] = (([]:[]):[]) ++ ([([x] ++ xs),ys]:[])
5
Programmierung WS14/15
Übungsblatt 9 (Abgabe 07.01.2015)
Aufgabe 7 (Listen in Haskell):
(1,5 + 1,5 + 1,5 + 1,5 + 2 = 8 Punkte)
Seien x, y 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.
: Die Liste [[1,2,3],[4,5]] hat den Typ [[Int]] und enthält 2 Elemente.
Hinweise:
ˆ Falls linke und rechte Seite gleich sind, genügt wiederum
Angabe des Typs und der Elementzahl.
Beispiel
eine
a)
x : ([y] ++ xs) = [x] ++ (y : xs)
b)
x:[y] = x:y
c)
x:ys:xs = (x:ys) ++ xs
d)
[x,x,y] ++ (x:xs) = x:x:((y:[x]) ++ xs)
e)
[]:[[[1]],[]] = [[],[1]]:[[]]
Tutoraufgabe 8 (Haskell-Programmierung):
Implementieren Sie alle der im Folgenden beschriebenen Funktionen in Haskell. Geben Sie jeweils auch die
Typdeklarationen an. Verwenden Sie auÿer Listenkonstruktoren [] und : (und deren Kurzschreibweise) und
Vergleichsoperatoren wie <=, ==,...
vordenierten Funktionen (dies schlieÿt auch arithmetische Operatoren ein), auÿer denen, die in den jeweiligen Teilaufgaben explizit erlaubt werden.
mult x y
Berechnet x · y. Sie dürfen dazu + und - verwenden. Die Funktion darf sich auf negativen Eingaben
beliebig verhalten.
keine
a)
bLog x
b)
Berechnet den aufgerundeten Logarithmus zur Basis 2 von x. Somit liefert bLog 1 den Wert 0, bLog 5
den Wert 3 und bLog 32 den Wert 5. Sie dürfen hier + und * verwenden. Die Funktion darf sich auf
negativen Eingaben oder der Eingabe 0 beliebig verhalten.
c)
getLastTwo xs
d)
singletons x
e)
packing xs ys
Das erste Argument xs ist eine Liste von Listen von Zahlen (vom Typ [[Int]]), das zweite Argument
ist eine einfache Liste von Zahlen (vom Typ [Int]). Die Funktion ersetzt leere Listen in der ersten
Eingabeliste durch einelementige Listen. Der Inhalt dieser einelementigen Listen ist die jeweils nächste
Zahl aus der zweiten Eingabeliste. Beispielsweise berechnet packing [[5,6],[],[8],[]] [1,2] die
Liste [[5,6],[1],[8],[2]]. Wenn im zweiten Argument nicht genug Zahlen zur Verfügung stehen,
werden zusätzliche leere Listen im ersten Argument leer gelassen. Wenn im zweiten Argument zu viele
Zahlen zur Verfügung stehen, werden diese ignoriert.
f)
listAdd x xs
Berechnet die Teilliste der letzten zwei Elemente der Int-Liste xs. Beispielsweise berechnet getLastTwo
[12, 7, 23] den Wert [7, 23]. Die Funktion darf sich auf Listen der Länge 0 und 1 beliebig verhalten.
Berechnet eine Liste mit x Elementen, wobei jedes Listenelement eine einelementige Liste ist. Die Elemente der einelementigen Listen sind die Zahlen x, x − 1, ..., 1. Beispielsweise berechnet singletons 3
die Liste [[3],[2],[1]]. Die Funktion darf sich auf negativen Eingaben beliebig verhalten. Sie dürfen
hier - verwenden.
Addiert jeweils das n-te Listenelement auf das (n+1)-te Listenelement, wobei auf das erste Listenelement
addiert wird. Beispielsweise berechnet listAdd 5 [1,9,3] die Liste [6,10,12]. Sie dürfen hier +
verwenden.
x
6
Programmierung WS14/15
Übungsblatt 9 (Abgabe 07.01.2015)
Aufgabe 9 (Haskell-Programmierung):
Punkte)
(1,5 + 1,5 + 2 + 2 + 3,5 + 2,5 = 13
Implementieren Sie alle der im Folgenden beschriebenen Funktionen in Haskell. Geben Sie jeweils auch die
Typdeklarationen an. Verwenden Sie auÿer Listenkonstruktoren [] und : (und deren Kurzschreibweise), der
Listenkonkatenation ++, Vergleichsoperatoren wie <=, ==, ... und arithmetischen Operatoren wie +, *, ...
vordenierten Funktionen auÿer denen, die in den jeweiligen Teilaufgaben explizit erlaubt werden oder
in früheren Teilaufgaben implementiert wurden.
Die arithmetischen Funktionen mod und div berechnen die Modulo-Operation bzw. die IntegerDivision. Beide Funktionen dürfen Sie ebenfalls verwenden.
keine
Hinweis:
a)
factorial x
x!
b)
digitSum x
c)
onlyEven xs
d)
reverses xs
e)
permutations xs
f)
anagram xs ys
True
False
Berechnet . Die Funktion darf sich auf nicht-positiven Eingaben beliebig verhalten.
Berechnet die Quersumme einer Zahl, d.h. die Summe der Ziern dieser Zahl. Beispielsweise ergibt
digitSum 345 den Wert 12. Die Funktion darf sich auf negativen Eingaben beliebig verhalten.
Berechnet die Teilliste der übergebenen Liste, welche genau die geraden Elemente der Ursprungsliste
in der gleichen Reihenfolge enthält. Beispielsweise berechnet onlyEven [12, 7, 23, 4, 5] den Wert
[12, 4].
Berechnet zu einer Liste von Zahlen eine Liste von Listen von Zahlen, wobei die erste Liste in der
Ergebnisliste genau die erste Zahl der Ursprungsliste enthält. Die zweite Liste in der Ergebnisliste enthält
die zweite Zahl der Ursprungsliste gefolgt von der ersten Zahl. Danach kommt die Liste bestehend aus
der dritten Zahl vor der zweiten und der ersten usw. Beispielsweise berechnet reverses [1,9,3] die
Liste [[1], [9,1], [3,9,1]].
Berechnet eine Liste aller Permutationen der übergebenen Liste. Beispielsweise berechnet permutations
[1,2,3] die Liste [[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]. Auf Listen, in denen es
ein Element gibt, das mehr als einmal in dieser Liste vorkommt, darf sich Ihre Implementierung beliebig
verhalten.
Liefert zurück, falls die Liste ys eine Permutation der Liste xs ist. Falls das nicht der Fall ist, liefert
die Funktion
als Ergebnis. Auf Listen, in denen es ein Element gibt, das mehr als einmal in dieser
Liste vorkommt, darf sich Ihre Implementierung beliebig verhalten.
7
Herunterladen