Technische Universität München Institut für Informatik Lehrstuhl für Computer Graphik & Visualisierung Praktikum: Grundlagen der Programmierung Prof. R. Westermann, R. Fraedrich, R. Fülöp, H.G. Menz WS 2009 Aufgabenblatt 6 2. Dezember 2009 Abgabe: In KW 50/51 (10. Dezember – 16. Dezember) vor der Übung. Listen, Keller, Schlangen, Sortierung Die Evaluation zu dem Praktikum finden Sie ab Donnerstag auf http://pgdp.in.tum.de. 6.1 (Ü) Wiederholung: Datentypen, Klassen Formal bezeichnet ein Datentyp in der Informatik die Zusammenfassung von Objektmengen mit den darauf definierten Operationen. (aus Wikipedia) Erklären Sie die Unterschiede und Gemeinsamkeiten von primitiven Datentypen und Klassen: (a) Kurz: Welche primitiven Datentypen haben Sie bereits kennengelernt bzw. verwendet? Und welche Klassen? (b) Wer legt fest, welche Datentypen existieren? Wo kann man das nachlesen? (c) Welche Operationen sind erlaubt? Wer legt diese fest? Gibt es nur binäre Operationen? (d) Erklären Sie die Begriffe Infix-, Präfix- und Postfix-Notation. 6.2 (Ü) Fragen zu Klassen (a) Wie sieht eine einfach verkettete Liste aus? Wie eine doppelt verkettete? (b) Erklären Sie die grundlegenden Konzepte hinter den Begriffen LIFO, FIFO, Stack (Keller), Queue (Schlange). Erklären Sie, wie man die gebräuchlichsten Operationen dieser Klassen implementieren würde (v.a. Einfügen und Entfernen von Elementen). (c) Man kann eine Klasse “Liste” entweder mit Hilfe eines Arrays oder mit Hilfe einer verketteten Liste implementieren. Diskutieren Sie Vor- und Nachteile dieser beiden Herangehensweisen. (d) Was ist ein Baum? Was ist ein Binärbaum? Wie ordnet man Objekte zu einer Baumstruktur an? (e) Was ist ein Pfad? Was ist die Höhe eines Baumes? Was ist ein balancierter Baum? (f) Baumtraversierung: Erklären Sie die Begriffe Breitensuche, Tiefensuche, Pre-Order-, In-Orderund Post-Order-Traversierung. 1 6.3 (Ü) Listen Im Folgenden wird eine Möglichkeit vorgestellt eine einfach verkettete Liste zu implementieren. Zunächst wird eine Klasse benötigt die ein einzelnes Element der Liste speichert, in diesem Fall ein int. Weiterhin enthält die Klasse eine Referenz auf das nachfolgende Element. null bedeutet, dass kein nachfolgendes Element existiert. public class IntegerItem { public int value ; public IntegerItem next = null ; IntegerItem ( int i ) { value = i ; } } Die eigentliche Liste wird in der Klasse de.tum.ws2009.grprog.uebungsblatt06.list.IntegerSingleLinkedList implementiert. Das erste Element der Liste wird in head gespeichert. public class I n t e g e r S i n g l e L i n k e d L i s t { p r i v a t e I n t e g e r I t e m head = n u l l ; p u b l i c v o i d add ( i n t v ) { I n t e g e r I t e m i t e m = new I n t e g e r I t e m ( v ) ; i t e m . n e x t = head ; head = i t e m ; } p u b l i c boolean d e l e t e ( i n t i ) { int counter = 0; I n t e g e r I t e m c u r r = head ; IntegerItem last = null ; w h i l e ( c u r r != n u l l ) { i f ( c o u n t e r == i ) { i f ( l a s t == n u l l ) head = head . n e x t ; else l a s t . next = curr . next ; return true ; } ++c o u n t e r ; last = curr ; curr = curr . next ; } 2 return f a l s e ; } public String toString () { String result = ” [ ” ; f o r ( I n t e g e r I t e m c u r r = head ; c u r r != n u l l ; curr = curr . next ) { r e s u l t += c u r r . v a l u e ; i f ( c u r r . n e x t != n u l l ) r e s u l t += ” , ” ; } return r e s u l t + ” ] ” ; } p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) { I n t e g e r S i n g l e L i n k e d L i s t l i s t = new I n t e g e r S i n g l e L i n k e d L i s t ( ) ; l i s t . add ( 1 ) ; l i s t . add ( 2 ) ; l i s t . add ( 8 ) ; System . o u t . p r i n t l n ( l i s t ) ; l i s t . delete (1); System . o u t . p r i n t l n ( l i s t ) ; } } Was ist die Ausgabe dieses Programmes? Wofür gibt es in der Methode boolean delete(int i) eine Referenze last? Wann gibt boolean delete(int i) den boolschen Wert true zurück und wann false. Erstellen Sie nun eine Membermethode, die alle Vorkommen einer Zahl in der Liste löscht. 6.4 (Ü) Verkettete Listen Realisieren Sie nun ein Adressbuch mit Hilfe einer einfach verketteten Liste. Erstellen Sie hierzu die Klasse AddressbookItem die eine Instanz von Friend und einen Zeiger next auf das nächste Element der Liste enthält. In der Klasse SingleLinkedListAddressbook sollen nun folgende Methoden angeboten werden: (a) public void add(Friend f) fügt einen Eintrag zu dem Adressbuch hinzu. (b) public String toString() gibt die Elemente der Liste in einem String zurück. (c) public void delete(int i) löscht den i-ten Eintrag aus dem Adressbuch. (d) public void delete(String name) löscht den ersten Eintrag mit dem Nachnamen name aus dem Adressbuch. (e) public SingleLinkedListAddressbook append(SingleLinkedListAddressbook addressBook) fügt ein anderes Addressbuch zu diesem hinzu und gibt eine neue Liste zurück, die alle Elmente der ursprünglichen und die der übergebenen Liste enthält. 3 Testen Sie Ihre Liste mit geeigneten Ein- und Ausgaben. 6.5 (Ü) Support Für den IT-Support soll ein Ticketsystem erstellt werden. Implementieren Sie hierfür eine Klasse Support, die neue Anfragen mit public void add(Ticket ticket) anlegt. Mitarbeiter können mit der Methode public Ticket get() die älteste Anfrage abrufen. Erstellen Sie hierfür eine Klasse Ticket. Ein Ticket enthält einen Namen, eine Email Adresse und eine Anfrage. Alle drei sollen über eine public String toString() Methode ausgegeben werden können. Welche Datenstruktur bietet sich am ehesten für diese Problemstellung an. Verwenden Sie die besprochene einfach verkette Liste als Basis für Ihre Lösung. 6.6 (H) Binärbaum (14 Punkte) In dieser Aufgabe werden wir ein Adressbuch auf der Grundlage eines Binärbaums implementieren. Erstellen sie eine Klasse, die einen Knoten im Binärbaum repräsentiert. Sie erinnern sich: Jeder Knoten eines Baumes ist selbst wieder die Wurzel eines Baumes. Ein Binärbaum und ein (beispielhaftes) UML-Diagramm der zu erstellenden Knotenklasse Als “Nutzlast” soll jeder Knoten eine Instanz der Klasse Friend (siehe Übungsblatt 5) enthalten. Der Binärbaum soll geordnet sein, d.h. die Knoten des Baumes sind stets nach einem bestimmten Schema sortiert. In unserem Fall sind die Nutzdaten vom Typ Friend. Bei Kontakten ist eine Sortierung wie im Telefonbuch (zuerst Nachnahme, dann Vorname) naheliegend. Die Friend-Klasse bietet eine Methode compareTo, mit deren Hilfe man die Reihenfolge zweier Adressbucheinträge bestimmen kann. Nutzen Sie diese Methode, um beim Modifizieren des Baumes sicherzustellen, dass immer und für jeden Knoten (und nicht nur für die Wurzel) gilt: Alle Kontakte im linken Unterbaum kommen vor dem Kontakt im aktuellen Knoten und alle Kontakte im rechten Unterbaum kommen nach dem Kontakt im aktuellen Knoten. Baumstruktur Implementieren Sie: 4 (a) Die Knotenklasse de.tum.ws2009.grprog.uebungsblatt06.BinaryTree selbst. Ein Knoten enthält Nutzdaten und seine beiden Kinder. Ihre Knotenklasse soll außerdem (mindestens) folgende Methoden enthalten: (b) public boolean isLeaf(): Gibt an, ob ein Knoten ein Blatt ist oder nicht. (c) public int getNumberOfNodes(): Liefert die Zahl der Knoten eines Baumes (einschließlich des Wurzelknotens). (d) public int getHeight(): gibt die Höhe des Baumes zurück, dessen Wurzel dieser Knoten ist. Die Höhe eines Baumes ist definiert als Länge des längsten Pfades von der Würzel zu einem Blatt. Beispiel: Ein Baum, der nur aus der Wurzel besteht, hat also Höhe 0; ein Baum bestehend aus zwei Knoten hat Höhe 1. Traversierung Schreiben Sie drei Methoden, die jeweils den Inhalt des Baumes als String zurückgeben. Der String soll aus mehreren Zeilen bestehen, eine Zeile pro Kontakt. Benutzen sie Friend.toString(), um einen Kontakt in einen String umzuwandeln. Einen Zeilenumbruch fügen sie mit der Zeichenkette \n an. (e) public String toStringPreOrder(): Gibt die Kontakte eines Baumes in folgender Reihenfolge zurück: Zuerst den Kontakt in der Wurzel, dann die Kontakte des linken Teilbaumes und dann die Kontakte des rechten Teilbaumes. (f) public String toStringInOrder(): Gibt die Kontakte eines Baumes in folgender Reihenfolge zurück: Zuerst die Kontakte des linken Teilbaumes, dann den Kontakt in der Wurzel und dann die Kontakte des rechten Teilbaumes. (g) public String toStringPostOrder(): Gibt die Kontakte eines Baumes in folgender Reihenfolge zurück: Zuerst die Kontakte des linken Teilbaumes, dann die Kontakte des rechten Teilbaumes und dann den Kontakt der Wurzel. Welche der drei Methoden gibt die Kontakte in der “richtigen” Reihenfolge (Telefonbuchsortierung) zurück? Vermerken Sie dies im JavaDoc der entsprechenden Funktion. Einfügen und Suchen (h) public boolean insert(Friend data): Mit dieser Methode wird bei einem bestehenden Baum ein neues Datenelement eingefügt. Das Datenelement soll an die “richtige” Stelle im Baum eingefügt werden, so dass die oben beschriebene Sortierung der Knoten erhalten bleibt. Die Methode liefert true zurück, wenn das Element erfolgreich eingefügt werden konnte und false wenn bereits ein entsprechendes Element im Baum vorhanden war. Sie müssen sich nicht um die Balancierung des Baumes kümmern - durchlaufen Sie in ihrer Implementierung den Baum einfach bis zu einer Stelle, an der das neue Element als Blatt hinzugefügt werden kann. (i) public SingleLinkedListAddressbook find(String searchRequest): Liefert eine Liste zurück, welche alle Kontakte enthält, die zu einer gegebenen Suchanfrage passen. Zu der Anfrage “liese” würden z.B. die Kontakte Lieselotte Franzmaier, Anneliese Schmidthuber und Hans Fliesenleger passen. Die Ergebnisliste soll sortiert sein. 5