Fachrichtung 6.2 — Informatik Universität des Saarlandes Tutorenteam der Vorlesung Programmierung 1 Programmierung 1 (Wintersemester 2015/16) Aufgaben für die Übungsgruppen: 14 (Kapitel 15 & 16) 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. Reihungen Aufgabe 14.1 Schreiben Sie eine Prozedur swapPairwise: α array → unit, die in einer gegebenen Reihung die Komponenten vorne beginnend paarweise tauscht. Beispielsweise soll die Reihung [2, 3, 4, 5] durch diese Prozedur zu [3, 2, 5, 4] vertauscht werden. Bei einer ungeraden Anzahl an Komponenten darf die letzte Komponente unverändert bleiben. Aufgabe 14.2 (Sortieren durch Auswählen) Ein einfacher, als Sortieren durch Auswählen bezeichneter, Algorithmus geht beim Sortieren einer durch ihre linkeste und rechteste Position gegebenen nicht leeren Teilreihung (l, r) wie folgt vor: • Bestimme die Position m einer Komponente minimaler Größe. • Vertausche die Komponenten an den Positionen l und m. • Sortiere die Teilreihung (l + 1, r). Schreiben Sie eine Prozedur ssort: int array → unit, die Reihungen durch Auswählen sortiert. Bestimmen Sie die Laufzeit Ihrer Prozedur. Imperative Schlangen Aufgabe 14.3 Erweitern Sie imperative Schlangen um (a) eine Operation add: α queue → α → unit, die ein Element in konstanter Laufzeit vorn an eine Schlange anfügt. (b) eine Operation delete: α queue → unit, die das letzte Element einer Schlange in linearer Laufzeit entfernt. Wenn nötig, werfen Sie Empty. Aufgabe 14.4 Ergänzen Sie die Signatur und Implementierung der imperativen Schlangen aus dem Buch (S. 312) um eine Prozedur insertPosition: α queue → α → int → unit, die, gegeben eine Schlange, einen Wert x und eine Zahl n, einen neuen Eintrag mit Inhalt x an die n-te Position der Schlange einfügt. Für Position 0, soll das Element als Kopf der Schlange eingefügt werden, für Position 1 als zweites Element usw. Sollte die übergebene Position die Länge der Schlange überschreiten, soll der Eintrag wie gewohnt an das Ende der Schlange angefügt werden. Hinweis: Überlegen Sie sich zunächst eine sinnvolle Hilfsprozedur, die Sie innerhalb der Struktur deklarieren. Diese Prozedur soll es Ihnen ermöglichen, einen neuen Eintrag zwischen zwei bereits existierenden Einträgen der Schlange einzufügen. 1 Schleifen Aufgabe 14.5 (Kleine Gemeinheit) Was tut das folgende Programm? let val i = 0 val n = 1 val _ = while ( i < 10) do ( i = n + 1; n = n * i ) in n end Aufgabe 14.6 Nutzen Sie im Folgenden while-Schleifen. Verzichten Sie auf Rekursion. (a) Schreiben Sie eine Prozedur gauss: int → int, die die Summe aller Zahlen von 0 bis zu einer Eingabe n berechnet. (b) Schreiben Sie eine Prozedur fib: int → int, die die n-te Fibonacci-Zahl berechnet. (c) Schreiben Sie eine Prozedur prim: int → bool, die prüft, ob eine Eingabe n eine Primzahl ist. (d) Schreiben Sie eine Prozedur sum: int list → int, die die Zahlen einer Liste von Zahlen aufaddiert. (e) Schreiben Sie eine Prozedur foldli: (α * β → β) → β → α list → β, die Faltung von links implementiert. Aufgabe 14.7 Betrachten Sie die folgenden Prozeduren. Geben Sie semantisch äquivalente Prozeduren an, die nicht rekursiv sind, sondern Schleifen benutzen. Hinweis: Stellen Sie zuerst sicher, dass die Prozedur endrekursiv ist. (a) fun pot 0 x a = a | pot n x a = pot ( n − 1) x ( a * x ) (b) fun square 0 = 0 | square n = square ( n − 1) + 2 * n − 1 (c) fun mystery n a b c d = if n + b + d < 0 then ( b + c ) * a else mystery ( n − 1) b a ( c * d ) ( d − a ) Aufgabe 14.8 (Reverse) Schreiben Sie eine Prozedur reverse: int array → unit, die eine Reihung mithilfe einer Schleife durch Umordnung Ihrer Komponenten reversiert. Halde/Linearer Speicher Aufgabe 14.9 Geben Sie die Werte aller allozierten Zellen an. Sie können dies (wie die Prozedur show) als Liste darstellen oder alternativ die verzeigerte Blockdarstellung benutzen. (a) val val val val a _ _ b = = = = new 10 update a 0 1 update a 1 1 iter 8 2 ( fn i ⇒ ( update a i ( sub a ( i−1) + sub a ( i−2)); i+1)) (b) val val val val val a _ _ _ _ = = = = = new 4 update update update update a a a a 0 1 2 3 ( a+2) ( a+0) ( a+3) ( a+1) 2 Aufgabe 14.10 Im Folgenden sollen Operationen auf der Halde (Buch S. 314) betrachtet werden. (a) Schreiben Sie eine Prozedur put: int → int → unit, die eine Zahl an eine Adresse schreibt. (b) Schreiben Sie eine Prozedur putints: int → int list → unit, die eine Folge von Zahlen hintereinander in die Halde schreibt. (c) Schreiben Sie eine Prozedur rev: int → int, die eine Liste reversiert. Sei dazu die Prozedur append: int → int → int, die zwei Listen konkateniert, gegeben. (d) Schreiben Sie eine Prozedur counter: unit → int, die in einer einzigen Speicherzelle einen Zähler implementiert, die beim n-ten Aufruf die Zahl n liefert. Die Halde sei leer. Aufgabe 14.11 (Lineare Darstellung von Listen) Sie haben in Kapitel 15.10 eine Möglichkeit kennen gelernt, Listen von Zahlen in einer Halde darzustellen. Auf diese können Sie die schon bekannten Prozeduren auf Listen aus Kapitel 4 anwenden. Allozieren Sie außer für tabulate keinen neuen Speicherplatz, wenn dies nicht unbedingt notwendig ist. (a) Schreiben Sie eine Prozedur length: address → int, die zu einer angegebenen Adresse die Länge der angegebenen verketteten Liste bestimmt. (b) Schreiben Sie eine Prozedur map: address → (int → int) → address, die auf die Liste einer angegebenen Adresse die Prozedur map anwendet. (c) Schreiben Sie eine Prozedur exists: address → (int → bool) → bool, die auf die Liste einer angegebenen Adresse die Prozedur exists anwendet. (d) Schreiben Sie eine Prozedur all: address → (int → bool) → bool, die auf die Liste einer angegebenen Adresse die Prozedur all anwendet. (e) Schreiben Sie eine Prozedur filter: address → (int → bool) → address, die auf die Liste einer angegebenen Adresse die Prozedur filter anwendet. Tipp: Sie benötigen eine Hilfsprozedur, um sich das letzte gültige Argument merken zu können. (f) Schreiben Sie eine Prozedur tabulate: int * (int → int) → address, die für eine Zahl n die Prozedur tabulate anwendet. (g) Schreiben Sie eine Prozedur rev: address → address, die die Liste einer Adresse reversiert. Stapelmaschinen Aufgabe 14.12 Geben Sie an, wie sich der Stapel bei der Ausführung der folgenden Programme schrittweise entwickelt. Zum Beispiel soll zu [con 1, con 2, sub, halt] die Entwicklung [ ] → [1] → [1, 2] → [1] angegeben werden. (a) [con 1, con 2, getS 0, getS 1, add, putS 0, halt] (b) [con 3, con 4, con 5, con 6, getS 3, getS 2, add, getS 1, getS 0, sub, halt] Aufgabe 14.13 Schreiben Sie Maschinenprogramme, die die folgenden Ausdrücke auswerten: (a) 20 + 7 − 3 (b) 20 + (7 − 3) (c) 1 + (2 + 3) ∗ (4 − 5) (d) if 2 ∗ 3 ≤ 12 − 3 then 3 else 5 (e) if (2 + 5) ≤ (1 ∗ 7) then (3 + 2) else (2 + 1) ∗ (3 + 4) 3 Aufgabe 14.14 (a) Schreiben Sie ein Programm, das zu einer natürlichen Zahl n mit einer Schleife die Fakultät n! berechnet. Schreiben Sie das Programm zuerst in SML und dann in M (dazu nehmen wir an, dass die Zahl n an der Position 0 auf dem Stapel liegt). Achten Sie darauf, dass Ihr Programm nur die Fakultät im Stapel zurücklässt. (b) Schreiben Sie ein Programm, das zu einer natürlichen Zahl n mit einer Schleife die Gauß-Summe für n berechnet. Aufgabe 14.15 Übersetzen Sie das folgende W -Programm in M : var n var res := 1 while 1 <= n do res := res * n n := n − 1 end Aufgabe 14.16 Scheiben Sie ein Programm (in W und M), das zu n die Liste [n, ..., 0] berechnet. Aufgabe 14.17 Schreiben Sie ein Maschinenprogramm, dass die Länge einer Liste berechnet. Halten Sie sich dabei an folgende Skizze in W: var xs var n := 0 while 0 <= xs do n := n + 1 xs := xs .1 end return n xs.1 liefert den Wert in der zweiten Zelle des Blocks, dessen Adresse der Wert der Variablen xs ist. Aufgabe 14.18 (Eigene Prozeduren aufrufen) Schreiben Sie ein Programm in M, welches mithilfe einer Prozedur, die das Minimum zweier Zahlen berechnet, den Ausdruck min(17, 8) − min(5, 7) berechnet. Aufgabe 14.19 Übersetzen Sie die folgende Prozedur nach M: fun fac n = if n < 2 then 1 else fac ( n − 1) * n Nehmen Sie dabei an, dass die Befehlssequenz für die Prozedur im Programmspeicher mit der Adresse 0 beginnt. Aufgabe 14.20 Übersetzen Sie die folgende Prozedur nach M: fun fib n = if n < 2 then n else fib ( n − 2) + fib ( n − 1) Aufgabe 14.21 (Rätsel) Was tut das folgende Programm? Das Programm erwartet, dass zwei Argumente auf dem Stack liegen, bevor es ausgeführt wird. [( getS 0) , ( con 1) , ( getS 1) , leq , ( cbranch 2) , ( branch 8) , ( getS 0) , mul , ( con 1) , ( getS 1) , sub , ( putS 1) , ( branch ∼11) , halt ] 4