IS S SA R 14. Übungsblatt zu Programmierung, WS 04/05 S UN E R SIT A IV A VIE N Prof. Dr. Gert Smolka, Dipl.-Inform. Guido Tack http://www.ps.uni-sb.de/courses/prog-ws04/ Lesen Sie im Skript: Kapitel 13 Aufgabe 14.1 Zu welchem Wert evaluiert der Ausdruck ref 1 = ref 1 ? Begründen Sie ihre Antwort. Aufgabe 14.2 (Generatoren) Ein Generator für eine Folge x1 , x2 , . . . von Werten eines Typs t ist eine Prozedur unit → t, die beim n-ten Aufruf xn liefert. a) Schreiben Sie einen Generator nextSquare für die Folge 0, 1, 4, 9, . . . der Quadratzahlen. b) Schreiben Sie eine Prozedur newNextSquare : unit → unit → int, die bei jedem Aufruf einen neuen Generator für die Folge der Quadratzahlen liefert. c) Schreiben Sie eine Prozedur newGenerator : (int → α) → unit → α, die zu einer Prozedur f einen Generator für die Folge f 0, f 1, f 2, . . . liefert. d) Schreiben Sie eine Prozedur newNextPrime : unit → unit → int, die bei jedem Aufruf einen neuen Generator für die Folge 2, 3, 5, 7, . . . der Primzahlen liefert. 2005–02–09 14:04 Aufgabe 14.3 (Binäre Suche) Eine Reihung des Types int array heißt sortiert, wenn ihre Komponenten aufsteigend sortiert sind. Schreiben Sie eine Prozedur member : int array → int → bool, die zu einer sortierten Reihung a und einer Zahl x entscheidet, ob eine Komponente von a den Wert x hat. Für Reihungen der Länge n soll member die Laufzeit O(log n) haben. Die logarithmische Laufzeit läßt sich mithilfe einer Technik erreichen, die als binäre Suche bezeichnet wird. Dafür stellen wir uns die sortierte Reihung als eine Folge vor, die von links nach rechts läuft, und gehen wie folgt vor: 1. Bestimme einen Index m, der etwa in der Mitte der Reihung liegt. 2. Wenn x der Wert der m-ten Komponente ist, liefere true. 3. Wenn x kleiner als der Wert der m-ten Komponente ist, suche in der linken Teilreihung weiter. 4. Wenn x größer als der Wert der m-ten Komponente ist, suche in der rechten Teilreihung weiter. 5. Wenn die zu durchsuchende Teilreihung leer ist, liefere false. Eine Teilreihung können wir durch das Paar aus ihrem kleinsten und größten Index darstellen. Aufgabe 14.4 Sie sollen eine Prozedur rotate : α array → unit schreiben, die die Komponenten einer nichtleeren Reihung um eine Position nach rechts schiebt. Dabei soll die letzte Komponente an die Stelle der ersten Komponente rücken. a) Schreiben Sie rotate mithilfe einer iterativ rekursiven Hilfsprozedur rotate 0 . b) Schreiben Sie rotate mithilfe einer Schleife. Aufgabe 14.5 Geben Sie eine möglichst kleine gewurzelte Listenstruktur an, die zwei verschiedene Knoten enthält, die denselben Zustand haben. Aufgabe 14.6 Wir betrachten Listenstrukturen mit Marken aus int und nennen einen Knoten sortiert, wenn er azyklisch ist und seine Liste aufsteigend sortiert ist. Schreiben Sie eine Prozedur enter : int node → int → unit, die in die Listenstruktur eines sortierten Knotens v einen neuen Knoten mit der Marke x so einfügt, dass v weiterhin sortiert ist. Aufgabe 14.7 Schreiben Sie eine Prozedur circle : int → intnode, die zu n ≥ 1 eine zyklische Listenstruktur der Form 1 2 2005–02–09 ... 14:04 n erzeugt. Als Ergebnis soll der mit 1 markierte Knoten geliefert werden. Aufgabe 14.8 Schreiben Sie eine Prozedur nodes : α node → α node list, die alle von einem Knoten aus erreichbaren Knoten liefert. Die Prozedur soll auch für zyklische Knoten funktionieren. Verwenden Sie eine Hilfsprozedur nodes 0 , die sich in einem Akkumulatorargument alle besuchten Knoten merkt. Geben Sie die Laufzeit Ihrer Prozedur an. Aufgabe 14.9 Schreiben Sie eine Prozedur iscircle : α node → bool, die testet, ob ein Knoten auf einem Zyklus liegt. Vorsicht: Nicht jeder zyklische Knoten liegt auf eiem Zyklus. Die Laufzeit von iscircle soll linear bezüglich der Größe der Listenstruktur des Knotens sein. Aufgabe 14.10 (Effiziente imperative Schlangen) Schreiben Sie eine Struktur, die imperative Schlangen gemäß der folgenden Spezifikation realisiert: eqtype ’a queue val queue : unit → ’a queue val insert : ’a * ’a queue → unit val head : ’a queue → ’a (* Empty *) val remove : ’a queue → unit (* Empty *) val empty : ’a queue → bool Die Operation queue liefert eine neue Schlange, die noch keine Einträge enthält. Die Operation insert trägt einen Wert in eine Schlange ein. Die Operation head liefert den ältesten Eintrag in einer Schlange. Die Operation remove entfernt den ältesten Eintrag aus einer Schlange. Die Operation empty testet, ob eine Schlange Einträge enthält. Alle Operationen sollen konstante Laufzeit haben. Sie sollen die Schlangen mithilfe einer Listenstruktur realisieren, die die in der Schlange stehenden Einträge enthält. Eine imperative Schlange soll durch ein Paar (v, r) : α node ∗ α node ref wie folgt dargestellt werden: (1) Die Liste des Knoten v besteht aus den in der Schlange stehenden Einträgen, wobei der älteste Eintrag ganz vorne und der jüngste Eintrag ganz hinten steht; (2) Die Referenz r zeigt auf den letzten Knoten der mit v beginnenden Listenstruktur. 2005–02–09 14:04