Fachrichtung 6.2 — Informatik Universität des Saarlandes Tutorenteam der Vorlesung Programmierung 1 Programmierung 1 (Wintersemester 2015/16) Wiederholungstutorium Blatt 13 (Queues, Binary Search) Hinweis: Dieses Übungsblatt enthält von den Tutoren für das Wiederholungstutorium erstellte Aufgaben. Die Aufgaben und die damit abgedeckten Themenbereiche sind für die Klausur weder relevant noch irrelevant. Aufgabe 13.1 (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). (a) Ü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 (b) Macht es Sinn Binäre Suche auf Listen zu implementieren? Wenn ja, geben Sie eine passende Darstellungsinvariante an. Wenn nein, nennen Sie Argumente, welche dagegen sprechen. Aufgabe 13.2 (Effiziente Schlangen) Sei die Signatur von Schlangen folgendermaßen gegeben: signature QUEUE = sig type α queue val empty : α queue val snoc : α queue → α → α queue val head : α queue → α val tail : α queue → α queue end (* Empty *) (* Empty *) (a) Überlegen Sie sich nun eine passende Darstellungsinvariante für eine effiziente Schlange, bei der alle Operationen akkumuliert betrachtet konstante Laufzeit haben. Hinweis: Die Schlange ist ein Paar aus zwei Listen (b) Geben Sie eine Implementierung für Schlangen an, die ihre Darstellungsinvariante erfüllt. (c) Erweiteren Sie diese Implementierung von Schlangen um eine Operation length: α queue → int, die die Länge einer Schlange mit konstanter Laufzeit liefert. Stellen Sie die Schlangen durch Tripel (q, r, n) dar und formulieren Sie die Invariante für die neue Darstellung. 1 Aufgabe 13.3 (Priorisierte Schlangen) Bei den Einträgen einer priorisierten Schlange handelt es sich um Paare (p, x), die aus einer Priorität p ∈ Z und einem Wert x bestehen. Bei der Erweiterung einer priorisierten Schlange um einen Eintrag (p, x) wird dieser so in die Schlange eingetragen, dass alle bisherigen Einträge mit einer Priorität ≥ p vor ihm und alle bisherigen Einträge mit einer Priorität < p nach ihm zu stehen kommen. (a) Geben Sie eine Signatur für priorisierte Schlangen an. (b) Geben Sie eine Implementierung für priorisierte Schlangen an. (c) Geben Sie die Darstellungsinvariante Ihrer Implementierung an. Aufgabe 13.4 (Puzzle) Für eine abstrakte Datenstruktur stellt sich oft die Frage, ob eine gewünschte Operation mit den Operationen der Struktur programmiert werden kann. Dazu wollen wir eine Abstrakte Datenstruktur Puzzle betrachten, die endliche Mengen ganzer Zahlen gemäß der folgenden Signatur bereitstellt: signature PUZZLE = sig type set val set : int list → set val find : ( int → bool ) → set → int option end Die Operation set soll zu einer Liste die entsprechende Menge liefern, und die Operation find soll zu einer Eigenschaft und einer Menge ein Element der Menge liefern, das die Eigenschaft erfüllt. (a) Deklarieren Sie eine Struktur Puzzle, die die abstrakte Datenstruktur Puzzle realisiert. (b) Schreiben Sie mit Hilfe der Operationen der Struktur Puzzle eine Prozedur set2list: set → int list, die die Elemente einer Menge als Liste liefert. Aufgabe 13.5 (a) Implementiere einen Konstruktortyp ktree, welcher in konstanter Zeit auf seine Unterbäume zugreifen kann. (b) Implementiere nun eine Prozedur atAdress: ktree → int list → ktree, welche den Teilbaum eines ktrees an einer Adresse liefert. Aufgabe 13.6 (Binäre Suchbäume) Ein binärer Suchbaum ist ein binärer Baum, bei dem die Knoten des linken Teilbaums eines Knotens nur kleinere Schlüsselwerte und die Knoten des rechten Teilbaums eines Knotens nur größere Schlüsselwerte als der Knoten selbst besitzen. Gleichgroße Schlüsselwerte sind nicht erlaubt. Die Knoten des Baums sollen als int ∗ α Tupel dargestellt werden, wobei der erste Wert der Schlüsselwert und der zweite die Knotenmarkierung ist. Die Operation empty soll einen leeren Baum erzeugen, addN ode soll einen neuen Knoten an der richtigen Stelle im Baum einfügen, und getV alue soll zu einem Schlüsselwert die Knotenmarkierung liefern. Die Operation getP arentV alue soll zu einem Schlülsselwert die Knotenmarkierung des Vorgängers liefern, und getRightSubtree soll zu einem Schlüsselwert den rechten Unterbaum liefern. Benutzen sie intern folgenden Datentyp: datatype α bstr = NULL | L of α * α bstr * α bstr signature TREE = sig type α searchTree val empty = α searchTree val addNode = α searchTree → ( int * α ) → α searchTree val getValue = α searchTree → int → α option val getParentValue = α searchTree → int → α option val getRightSubtree = α searchTree → int → α searchTree option val getLeftSubtree = α searchTree → int → α searchTree option end 2 Aufgabe 13.7 (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 3