Algorithmen und Datenstrukturen Universität Konstanz Fachbereich Informatik & Informationswissenschaft WS 2015/2016 Prof. Dr. Ulrik Brandes / Arlind Nocaj / Felix Schönenberger 7. Übungsblatt Ausgabe: 3. Dezember 2015 Abgabe: 9. Dezember 2015, 18:00 Uhr Die Bearbeitung in Zweiergruppen ist ausdrücklich erwünscht. Aufgabe 1: Baumdurchläufe 5 Punkte Analog zur Inorder-Reihenfolge der Knoten eines Binärbaumes T sind Preund Postorder durch entsprechende Baumdurchläufe definiert (Aufruf mit T.root): Algorithmus 1 : preorder Algorithmus 2 : postorder preorder(v)begin if v 6= nil then print v.key preorder(v.left) preorder(v.right) postorder(v)begin if v 6= nil then postorder(v.left) postorder(v.right) print v.key (a) Geben Sie den Binärbaum mit folgender Pre- und Inorder an: Preorder: Inorder: 17, 42, 8, 15, 6, 30, 14 8, 42, 6, 15, 17, 14, 30 (b) Zeigen Sie, dass die Struktur eines Binärbaums durch seine Pre- und Inorder eindeutig bestimmt ist. (c) Ist die Struktur eines Binärbaums durch seine Pre- und Postorder eindeutig bestimmt? [Bitte wenden] Aufgabe 2: AVL-Bäume 5 Punkte (a) Führen Sie folgende Operationen auf einem anfangs leeren AVL-Baum aus, und geben Sie den Zustand des Baumes nach jeder Operation an. Dokumentieren Sie auch einfache oder doppelte Rotationen. insert(4), insert(8), insert(9), insert(6), insert(5), insert(7), remove(6), remove(5) Gehen Sie beim Löschen von der Strategie „Suche größten Nachfahren im linken Teilbaum“ aus (Algorithmus 23 im Skript), und wählen Sie gegebenenfalls bei gleicher Höhe der Teilbäume von Knoten v den Knoten w als linkes Kind von v (anstatt beliebig, vgl. S. 51 im Skript). (b) Geben Sie einem AVL-Baum und auf diesem eine remove- Operation an, welche mehr als eine (Doppel-)Rotation auslöst. Dokumentieren Sie diese Operation. Aufgabe 3: Binäre Suchbäume 4 Punkte Realisieren Sie einen (unbalancierten) binären Suchbaum. Implementieren Sie dazu das Interface material.p03.BinaryTree in einer Klasse groupXX.p03.BinarySearchTree. Die Baumknoten sollen das Interface material.p03.BinaryTree.Node implementieren. Achten Sie darauf, dass die Methode size() den gewünschten Wert in konstanter Zeit zurückgibt. Aufgabe 4: Höhenupdate 3 Punkte Die Höhe h(v) eines Knotens v ist definiert durch 0 wenn v ein Blatt ist h(v) = 1 + max(h(v.lef t), h(v.right)) sonst Die Höhe des Baumes entspricht dann der Höhe des Wurzelknotens. Stellen Sie sicher dass ein getHeight() Aufruf in konstanter Zeit den korrekten Wert zurückgibt. Implementieren Sie hierzu z.b. eine Methode protected void update(Node<K, V> node) und verwenden Sie diese in insert und delete so, dass nach diesen Operationen die Höheninformation an den notwendigen Knoten effizient aktualisiert wird. Aufgabe 5: Erweitertes find 3 Punkte Implementieren Sie die Methode Stream<V> findInterval(K min, K max). Diese soll einen Stream aller Werte ausgeben, die zu Knoten v gehören, für die min ≤ v.key ≤ max gilt. Die Reihenfolge der Elemente in der Liste soll der in-order-Reihenfolge der zugehörigen Knoten entsprechen. Achten Sie auf eine effiziente Implementation. findAll kann in Θ(h + s) realisiert werden, wobei h die Höhe des Suchbaums und s die Anzahl der gefundenen Knoten bezeichnet. Beachten Sie insbesondere, dass für balancierte Bäume h ∈ Θ(log n) gilt. Um Streams zu erzeugen kann der Stream.Builder verwendet werden. Stream.builder().add(/*value*/).build(); Allgemeine Hinweise: • Beachten Sie die Kommentare in den zur Verfügung gestellten Klassen. • Vergeben Sie sinnvolle Variablennamen. Variablennamen aus dem Skript können beibehalten werden. • Jeder Schlüssel darf im Suchbaum nur einmal vorkommen. • Um Ihre Implementierung zu testen erweitern sie die Klasse material.p03.BinarySearchTreeTest.