Algorithmen und Datenstrukturen Sommersemester 2012 Hochschule RheinMain Prof. Dr. Steffen Reith 8. Übungsblatt Aufgabe 1 (Bäume) Zur vollständigen Bearbeitung dieser Aufgabe sind die folgenden Punkte zu bearbeiten: • Implementieren Sie einen binären (Such)Baum in C. Achten Sie darauf, dass der Nutzdatentyp in Ihrem Quellcode leicht geändert werden kann (Durch geschickte Benutzung des C-Präprozessors kann man sich sogar eine einfache Version von Generics/templates nachbauen!). Zu implementieren sind auf jeden Fall die Methoden insert, PrintTreeInorder, getHeight und isEmpty. Die Methode PrintTreeInorder gibt alle Elemente eines Baums gemäß Inorder-Traversierung aus. Testen Sie dies mit dem Nutzdatentyp int geeignet. • Erweitern Sie nun Ihren binären Suchbaum um die Methode mergeInorder, die alle Elemente aus einem zweiten Baum gemäß Inorder-Traversierung in den aktuellen Baum einfügt, d.h. die Methode mergeInorder besucht (Inorder!) alle Knoten des zweiten Baums und fügt sie in den aktuellen Baum ein. • Schreiben Sie ein Testprogramm mit zwei int-Bäumen t1 und t2, die mit je 100 Zufallszahlen befüllt werden, wobei die Zufallszahlen für t1 aus dem Intervall [1, . . . , 1000] stammen und die für t2 aus dem Intervall [1001, . . . , 2000] (wichtig!). Danach soll Ihr Testprogramm die Höhen von t1 und t2 ausgeben. Nun verschmelzen Sie t1 mit t2 unter Benutzung von mergeInorder und geben die Höhe des verschmolzenen Baums aus. – Wie erklären Sie das Ergebnis der verhältnismässig großen Höhe des verschmolzenen Baums? – Planen (Pseudocode notwendig!) und implementieren Sie eine mit mergeInorder vergleichbare Methode, die einen Baum mit (deutlich) kleinerer Höhe liefert (Hinweis: Überlegen Sie sich eine geeignete Traversierungsstrategie für Ihre merge-Methode). Aufgabe 2 (Bäume) Zur vollständigen Bearbeitung dieser Aufgabe sind die folgenden Punkte zu bearbeiten: • Bis jetzt besteht der interne Knoten-Datentyp Ihrer (Such)Baumimplementierung nur aus einem Nutzdatenfeld, einer Referenz auf den linken Teilbaum und einer Referenz auf den rechten Teilbaum. Erweitern Sie nun den Knoten-Datentyp um eine Komponente balance vom Typ long. Die Balance eines Knotens v ist nun wie folgt definiert: Ist v ein Blatt des Baums, so hat er Balance 0. Ist der Knoten v kein Blatt, so berechnet sich die Balance von v wie folgt: balance = Höhe des linken Teilbaums von v - Höhe des rechten Teilbaums v . • Erweitern Sie Ihre (Such)Baumimplementierung um die Methoden void calculateBalanceAll(). Die Methode void calculateBalanceAll() berechnet die Balance aller Knoten des Baums und setzt die balance Komponente der Knoten auf den entsprechenden Wert. Erweitern Sie PrintTreeInorder, sodass nun auch die Balance der Knoten ausgegeben wird. (Hinweis: Die Methoden lassen sich durch Modifizierung der aus der Vorlesung bekannten Traversierungsalgorithmen leicht implementieren.) Aufgabe 3 (Bäume) Die Höhe eines Baums ist definiert als die Anzahl der Knoten in einem längsten Pfad von Knoten zu einem Blatt. Damit hat ein Baum der nur aus der Wurzel besteht schon die Höhe 1. Beweisen Sie, dass ein vollständiger trinärer Baum (jeder Knoten der kein Blatt ist hat genau 3 Kinder) der Höhe h genau (3h − 1)/2 Knoten enthält. Hinweis: Wissen über die Geometrische Reihe ist immer nützlich. Die Abnahme startet in der KW 23 ab dem 6.6.2012 Einige (optionale) Übungsaufgaben • Richtig oder falsch?: – Mergesort hat immer eine Laufzeit von O(n log n). – Insertion Sort hat immer eine Laufzeit von O(n log n). – Es gibt Sortierverfahren mit einer Laufzeit von O(log n). • Geben Sie die Laufzeit von Insertion Sort an und begründen Sie Ihre Antwort fundiert. • Gegeben sei T (n) = 3 · T (n/3) + n und T (1) = 0. Bestimmen Sie eine Funktion f , so dass T (n) = f (n). Dabei darf T nicht in der Beschreibung von f vorkommen. • Kann man in einer linearen Liste effizient mit der binären Suche arbeiten? Begründen Sie Ihre Antwort!