Technische Universität München Institut für Informatik Lehrstuhl für Bioinformatik Einführung in die Programmierung für Bioinformatiker Prof. B. Rost, L. Richter WS 2014/15 Aufgabenblatt 6 24.11.2014 Java, ADT 6.1 (Ü) Listen und Polymorphe In der folgenden Aufgabe entwickeln Sie objekt-orientiert eine Kombination aus dem abstrakten Datentyp Liste und polymorphen Nutzdaten. Genauer ausgedrückt handelt es sich um eine einfach verkettete Liste. Dieser ADT wird häufig auch als Queue bezeichnet. Die Liste wird durch eine Klasse, die die Funktionalität bereitstellt, gebildet und eine Klasse, die die Listenelemente enthält. Dementsprechend muss nur ein ”Verwaltungsobjekt” aber mehrere Objekte für die Listenelemente erzeugt werden. Um Erfahrung mit Polymorphie zu sammeln, handelt es sich bei den gespeicherten Nutzelementen um Objekte mit einer Vererbungsbeziehung. Der eigentliche Zusammenbau erfolgt dann innerhalb der main-Methode einer eigenen Treiberklasse. Die Liste unterstützt folgende Funktionen: • • • • addElement(...) fügt ein Element am Ende hinzu removeElement() entfernt das Element am Anfang und gibt es zurück getHead() gibt das Element am Anfang zurück toString(): Gibt eine numerierte Textdarstellung der Listenelemente aus Um das in Java zu implementieren, brauchen wir folgende Klassen: (a) Student: Wird mit einem Namen und einer Matrikelnummer erzeugt. toString() gibt den Namen und die Matrikelnummer in einer Zeile aus. (b) Fachschaft: Unterklasse von Student. Zusätzlich gibt es ein Amt, das bei der Erzeugung angegeben werden kann, oder erst später gesetzt wird. toString() gibt nach Name und Matrikelnummer meine Aufgabe in der Fachschaft: ünd die Aufgabe aus. (c) Listenelement: Enthält eine Referenz auf ein Student-Objekt und eine Referenz auf das nächste Listenelement. Gibt es keine nächstes Element ist der Wert null. (d) Liste: Implementiert die oben angegebenen Funktionen und enthält eine Referenz auf das erste Listenelement. (e) Driver : Dieser Klasse erzeugt in ihrer main()-Methode verschiedene Studenten und Fachschafter und speichtert sie in der Liste bzw. entfernt sie auch wieder. Die Liste wird zu verschiedenen Zeitpunkten am Bildschirm ausgegeben. 1 6.2 (Ü) Unveränderbarer Binärbaum Ein Binärbaum ist ein Baum, in dem alle Knoten einen Wert und 2 Teilbäume haben. Bei einem Binären Suchbaum (BSB) gilt für jeden Knoten des Baumes, dass sein Wert: • grösser ist als die Werte aller Knoten in seinem linken Teilbaum; • kleiner ist als die Werte aller Knoten in seinem rechten Teilbaum; • maximal einmal im ganzen BSB vorkommt. Man bezeichnet dies auch als Bauminvariante. Beispiel: In der obigen Zeichnung finden Sie einen BSB f:̈ur die Zahlen 1, 3, 6, 7, 8, 10, 13, 14. (a) Entwerfen und realisieren Sie eine Datenstruktur BinaryTree für binäre Suchbäume für ganze Zahlen (int). Auf die Objektattribute soll von außen nicht zugegriffen werden können. Außerdem sollen die Objektattribute nur initial bei der Deklaration oder durch den später zu implementierenden Konstruktor gesetzt werden und anschließend nicht mehr verändert werden können (final). Es soll eine unveränderliche ( immutable“) Datenstruktur implementiert werden! ” (b) Implementieren Sie einen Konstruktor, der eine ganze Zahlübergeben bekommt und damit einen Binärbaum initialisiert, der nur diese Zahl enthält. (c) Implementieren Sie einen privaten Konstruktor, der eine ganze Zahl sowie eine Referenz auf einen linken und einen rechten Teilbaum übergeben bekommt. Da dieser Konstruktor nur von der Klasse selbst verwendet werden kann, brauchen Sie an dieser Stelle nicht zu prüfen, ob die Bauminvariante möglicherweise verletzt wurde. Hinweis: Verwenden Sie diesen Konstruktor für die folgenden Methoden. Es bietet sich an, die folgenden Methoden rekursiv zu formulieren und zu programmieren: (d) Implementieren Sie eine Methode BinaryTree insert(int newElem), die eine Kopie dieses Baumes zurückgibt, die außerdem das neue Element beinhaltet. Achten Sie dabei auf die Einhaltung der Bauminvariante. Beispiel: Die folgende Zeichnung illustriert einen Aufruf von insert(4): insert(4) −→ (e) Implementieren Sie eine Methode boolean contains(int elem), die true zurückgibt, falls das übergebene Element im Baum vorkommt und false, falls nicht. (f) Implementieren Sie eine Methode String toString(), die eine Zeichenkettenrepräsentation der Baumstruktur zurückgibt. Beispiel: toString() liefert für den obigen linken Baum: (((null,1,null),3,(null,6,(null,7, null))),8,(null,10,((null,13,null),14,null))) (g) Implementieren Sie eine Methode int size(), die die Anzahl der Elemente des Baums zurückgibt. 2 (h) Implementieren Sie eine Methode int depth(), die die Tiefe des Baums zurückgibt, sprich die Anzahl der Kanten des längsten Pfades von der Wurzel bis zu einem Blatt (Blätter sind kinderlose Knoten). Ein einelementiger Baum hat also die Tiefe 0. (i) Optional: Implementieren Sie eine Methode String toStringDescending(), die die Elemente des Baums in absteigender Reihenfolge durch Kommata getrennt als Zeichenkette zurückgibt. (j) Optional: Implementieren Sie eine Methode boolean isBinarySearchTree(), die true zurückgibt, falls die Bauminvariante für diesen Baum gilt und false, falls nicht. 6.3 (Ü) Interfaces In dieser Aufgabe sollen die Klassen aus Blatt 5 (Geometrische Flächen und Prismen) erweitert werden. (a) Einerseits sollen Klassen vom Typ Prisma und Grundflaeche untereinander und miteinander vergleichbar gemacht werden in dem beide Klassen das Interface java.lang.Comparable implementieren. • Prismen werden nach Größe des Volumens (ist das Volumen gleich, dann zählt die größere Oberfläche) verglichen; • Grundflaechen werden nach Größe der Fläche verglichen; • Prismen werden über ihre Grundflaeche mit anderen Grundflaechen verglichen; (b) Testen Sie die Implementierung, indem Sie eine ArrayList von Grundflaeche mittels java.util. Collections.sort() sortieren. (c) Als zweiten Schritt sollen die Methoden istQuadrat und zuQuadrat in ein Interface Quadrierbar ausgelagert werden, welches nur von solchen Grundflaechen implementiert werden soll, die auch ein Quadrat darstellen können. (d) Fügen Sie eine weitere Grundflaeche Dreieck zur Modellierung von rechtwinkligen Dreiecken zu den bereits bestehenden Grundflaechen hinzu. Ein (rechtwinkliges) Dreieck wird durch die Länge der Hypotenuse und Ankathete parametrisiert. (e) Zuletzt erstellen wir ein weiteres Interface Polygon mit nur einer Methode int getEckenAnzahl(), welche die Zahl der in einer Grundfläche enthaltenen Ecken zurückgibt. (f) Implementieren Sie Polygon für alle Grundflaechen, die eine endliche Anzahl von Ecken besitzen. (g) Testen Sie Quadrierbar und Polygon, indem Sie über eine sortierte ArrayList vom Typ java.lang.Comparable, welches Prisma und Grundflaechen enthält, iterieren und mittels instanceof die Verfügbarkeit beider Interfaces abfragen und, falls vorhanden, die aus diesen Interfaces ermittelbaren Informationen ausgeben. 3