Übungsblatt aus Übung 13 - Universität des Saarlandes

Werbung
Fachrichtung 6.2 — Informatik
Universität des Saarlandes
Tutorenteam der Vorlesung Programmierung 1
Programmierung 1 (Wintersemester 2015/16)
Aufgaben für die Übungsgruppen: 13
(Kapitel 14 & 15)
Hinweis: Dieses Übungsblatt enthält von den Tutoren für die Übungsgruppe erstellte Aufgaben.
Die Aufgaben und die damit abgedeckten Themenbereiche sind für die Klausur weder relevant noch irrelevant.
Datenstrukturen
Aufgabe 13.1 (Snoc)
Schreiben Sie eine Prozedur snoc: α → α vector → α vector, die zu x und [x1, x2, x3, ..., xn] den
Vektor [x1, x2, x3, ..., xn, x] liefert.
Aufgabe 13.2
structure S = struct
val a = 4
fun f x = x + 1
end
Sei obige Struktur in der leeren Umgebung deklariert. Ist der Aufruf val test = f a in SML gültig?
Aufgabe 13.3
(a) Gegeben sei folgende Struktur:
(b) Gegeben sei folgende Struktur:
structure Ident :> sig
val id : string → string
val x : real
end
=
struct
fun id x = x
val x = id 14.4
end
structure Test :> sig
eqtype α ls
val new : α list → α ls
end
= struct
type α ls = α list
fun new xs = xs
end
Warum ist folgender Vergleich unzulässig, obwohl
α ls als Typ mit Gleichheit implementiert wurde?
Warum ist der Aufruf von Ident.id mit dem
Argument 13.4 nicht zulässig, obwohl die Prozedur polymorph implementiert wurde und in der
Struktur sogar mit dem Argument 14.4 aufgerufen wird?
val a = [1 ,3 ,5]
val b = Test . new a
val istGleich = a = b
Aufgabe 13.4
Schreiben Sie eine Struktur MyMath, die folgende Operationen enthält:
•
•
•
•
•
fac: int → int (berechnet die Fakultät einer natürlichen Zahl, wobei für n < 0 gilt: fac n = 0)
add: int * int → int (addiert zwei Ganzzahlen)
addr: real → real → real (addiert zwei Reals)
mul: int * real → real (multipliziert zwei Zahlen)
sum: int list → int (berechnet die Summe der Elemente einer Liste, wobei sum nil = 0)
Dabei sollen fac, mul und sum lineare Laufzeit und add und addr konstante Laufzeit haben.
1
Aufgabe 13.5 (Mengen I )
Seien Mengen von Ganzzahlen als strikt sortierte Listen dargestellt und folgende Signatur gegeben:
signature MYSET = sig
type set
val subset : set → set → bool
val union : set → set → set
end
(a) Schreiben Sie eine Struktur MySet, die folgende Operationen in linearer Laufzeit ausführen kann:
• subset: set → set → bool (testet, ob eine Menge Teilmenge einer anderen Menge ist)
• union: set → set → set (liefert die Vereinigung zweier Mengen)
(b) Schreiben Sie eine Prozedur equal: MySet.set → MySet.set → bool, die testet, ob zwei Mengen gleich
sind.
Aufgabe 13.6 (Mengen II )
Implementieren Sie eine Datenstruktur MySet2, die Mengen ganzer Zahlen darstellt. Die Datenstruktur soll
dabei folgende Signatur haben:
signature MYSET2 = sig
type set
val new : int list → set
val add : int * set → set
val min : set → int
val max : set → int
val del : int * set → set
end
Für die einzelnen Prozeduren sollen folgende Einschränkungen gelten:
• new soll aus einer Liste eine Menge erstellen und eine Komplexität in O(n2 ) haben.
• add soll ein weiteres Element in eine Menge einfügen. Die Komplexität von add soll O(n) sein.
• min und max sollen den kleinsten/größten Wert einer Menge zurückgeben und konstante Komplexität
besitzen. Ist die Menge leer, so soll die Ausnahme Empty geworfen werden.
• delete soll ein Element aus der Menge entfernen und lineare Komplexität besitzen.
Aufgabe 13.7 (Binäre Suche)
Gegeben sei ein sortierter Vektor, in dem nun nach einer bestimmten Komponente gesucht wird und deren
Position zurückgegeben werden soll. Anstatt nun von vorn nach hinten den ganzen Vektor zu durchlaufen und
jede Komponente zu überprüfen (lineare Suche), betrachten wir zuerst die Komponente in der Mitte des Vektors.
Falls es sich um die gesuchte Komponente handelt, ist die Suche schon beendet. Andernfalls wird die Suche
fortgesetzt auf entweder dem linken Teil oder dem rechten Teil des Vektors, je nachdem ob die mittlere
Komponente zu klein oder zu groß war.
Die Suchprozedur position: (α * α → order) → α vector → α → int option liefert einen Optionstypen zurück, da die Suche natürlich auch erfolglos sein kann. Die Hilfsprozedur position’ bekommt immer den
Bereich des Vektors übergeben, der durchsucht werden soll (left und right).
Überlegen Sie sich, welche Komplexität position hat, und komplettieren Sie die Prozedur:
fun position compare v x = let
fun position ’ left right =
if left > right then
...
else
...
in
position ’ 0 ( Vector . length v − 1)
end
2
Aufgabe 13.8 (Mysteriöse Listen)
Implementieren Sie eine Datenstruktur, die die folgende Signatur und die gegebenen Einschränkungen erfüllt:
signature MYSTERYLIST = sig
type α mlist
val empty : α mlist (* stellt eine leere Liste dar *)
val mlist : α list → α mlist
val cons : α → α mlist → α mlist
(* Fuegt ein Element in konstanter Zeit hinzu *)
val rev
: α mlist → α mlist (* Reversiert in konstanter Zeit *)
val hd
: α mlist → α
(* gibt das erste Element zurueck , Laufzeit egal *)
val tl
: α mlist → α mlist
(* gibt den tail der Liste in konstanter Zeit zurueck *)
end
Speicher
Aufgabe 13.9 (Statische Semantik für Speicheroperationen)
Ergänzen Sie folgende Inferenzregeln der statischen Semantik für Allokation, Dereferenzierung und Zuweisung:
Sref
T `
:
S!
T `
S:=
:
T `
:
Aufgabe 13.10 (Quiz I )
Wozu werten die folgenden Ausdrücke aus?
(a) ref 1 = ref
(b) ref 1 = ref
(c) val a = ref
val b = a
a = b
(d) ! ( ref 0) =
(e) ! ref 1 = !
(f) map ! [ ref 1 , ref 2 , ref 3]
= [ ref 1 , ref 2 , ref 3]
2
1
1
(g) map ! [ ref 1 , ref 2 , ref 3] = [1 , 2 , 3]
(h) map ! []
(i) map ! [] = []
ref 2
ref 1
(j) ref [1 , 2 , 3] = [ ref 1 , ref 2 , ref 3]
Aufgabe 13.11 (Quiz II )
Sind folgende Phrasen zulässig? Wenn ja, wozu werten sie aus?
(d) val rl = [ ref 1 , ref 2 , ref 3]
(a) map ! (! ( ref [2 ,5 ,21]))
foldr := 3 rl
(b) val ri = ref 8
rl
val rb = ref true
(e) val intref = ref 5
if true then ri else rb
val intref = ref ( intref := 3;
(c) val rl = [ ref 1 , ref 2 , ref 3]
! intref + 2; ! intref = 5)
foldr ( fn (x , s ) ⇒ ( x := s ; s )) 3 rl
rl
Aufgabe 13.12 (Quiz III )
Wie unterscheiden sich die folgenden Prozeduren?
•
•
•
•
val
val
fun
fun
c0
c1
c2
c3
= let val r = 0 in fn () ⇒ ( r = r
= let val r = ref 0 in fn () ⇒ ( r
() = let val r = ref 0 in ( r := ! r
() = let val r = ref 0 in fn () ⇒
+ 1; r ) end
:= ! r + 1; ! r ) end
+ 1; ! r ) end
( r := ! r + 1; ! r ) end
Aufgabe 13.13 (Quiz IV )
Wozu wertet dieser Ausdruck aus?
let fun mystery a b c d = b := !(#2 ( d := !a , d , d := ! c ))
val (a ,b ,c , d ) = ( ref 1 , ref 2 , ref 3 , ref 4)
in ( mystery a b c d ; (! a , !b , !c , ! d )) end
3
Aufgabe 13.14 (Generatoren)
(a) Schreiben Sie eine Prozedur zero: unit → int ref, die bei jedem Aufruf eine Referenz auf eine Speicherzelle zurückgibt, in der eine 0 steht. Die Speicherzelle muss nicht immer die gleiche sein.
(b) Schreiben Sie eine Prozedur n: int → int ref, die bei jedem Aufruf eine Referenz auf eine Speicherzelle
zurückgibt, in der eine Eingabe x steht.
(c) Deklarieren Sie einen Bezeichner c: unit → unit, der bei jedem Aufruf einen Zähler in einer Speicherzelle
um eins erhöht, sodass nach n Aufrufen die Anzahl der Aufrufe in der Speicherzelle stehen.
(d) Passen Sie c: unit → int ref so an, dass bei jedem Aufruf eine Referenz auf die Speicherzelle, die den
Zähler enthält, zurückgegeben wird.
(e) Schreiben Sie eine Prozedur p: int → unit → int, die eine Eingabe n in eine Speicherzelle schreibt
und eine Abstraktion zurückgibt, die bei jedem Aufruf den Inhalt der Speicherzelle verdoppelt und den
neuen Inhalt der Speicherzelle ausgibt.
(f) Schreiben Sie eine Prozedur q: unit → unit → int, die eine Prozedur zurückgibt, die nach n Aufrufen
die n-te Quadratzahl zurückgibt.
(g) Schreiben Sie eine Prozedur retimp: (α → α) → α → unit → α, die eine Prozedur zurückgibt, die
nach n Aufrufen das Ergebnis der n-fachen Anwendung einer Prozedur f auf einen Startwert s zurückgibt.
(h) Schreiben Sie eine Prozedur tausch: α ref → α ref → unit, die den Inhalt zweier Speicherzellen
miteinander vertauscht. Nutzen Sie keine lokalen Deklarationen.
(i) Schreiben Sie eine Prozedur fib: unit → unit → int, die eine Prozedur zurückgibt, die beim n-ten
Aufruf die n-te Fibonacci-Zahl zurückgibt.
Aufgabe 13.15
(a) Schreiben Sie eine Prozedur reffer: α list → α ref list, die zu einer Eingabeliste xs eine Liste
zurückgibt, die Referenzen enthält, deren Werte die Werte von xs sind.
(b) Schreiben Sie eine Prozedur dou: int ref list → unit, die die Werte der Referenzen einer Liste xs
verdoppelt. Nutzen Sie eine Hilfsprozedur.
(c) Schreiben Sie eine Prozedur sum: int list → int, die die Zahlen einer Liste xs aufaddiert. Die Summe
soll dabei in einer einzigen Speicherzelle akkumuliert werden. Nutzen Sie keine funktionalen Hilfsprozeduren.
(d) Schreiben Sie eine Prozedur effer: (α → β) → α list → β ref list ref, die eine Referenz auf
eine Liste zurückgibt, die Referenzen auf die Werte der Eingabeliste xs nach Anwendung einer Prozedur f
auf die einzelnen Werte enthält. Nutzen Sie beliebige Prozeduren. Für [1,2,3] und fn x ⇒ 2 * x soll
eine Referenz auf [ref 2, ref 4, ref 6] zurückgegeben werden.
Aufgabe 13.16 (Imperative Stapel)
Wir wollen Stapel als Datenstruktur implementieren. Stapel sind veränderliche Objekte. Sei die Signatur
eqtype α stack
val stack
val push
val pop
val top
val empty
:
:
:
:
:
unit → α stack
α stack → α → unit
α stack → unit
α stack → α
α stack → bool.
Alle Operationen sollen konstante Laufzeit haben. stack erzeugt einen leeren Stapel, push fügt ein Element
vorn hinzu, pop löscht das erste Element, top liefert das erste Element, empty prüft, ob ein Stapel leer ist, und
size gibt die Anzahl der Elemente im Stapel zurück.
(a) Welche Konsequenz hat es für unsere Implementierung, dass Stapel veränderliche Objekte sind?
(b) Schreiben Sie die Signatur in SML und implementieren Sie Stapel.
4
Herunterladen