Technische Universität München Fakultät für Informatik A. Berlea, M. Petter, Dr. M. Schneider, P. Ziewer WS 2004/2005 Lösungsvorschläge zu Blatt 8 16. Dezember 2004 Übungen zu Einführung in die Informatik I (Vorversion) Aufgabe 23 Abstrakte Klassen (Lösungsvorschlag) a) Sinnvollerweise werden die beiden Oberklassen Prisma und Regelmäßiges Prisma abstrakt deklariert. Das ergibt dann folgendes Klassendiagramm: Prisma # hoehe: Double + abstract inhaltGrundflaeche(): Double + abstract umfangGrundflaeche(): Double + mantelFlaeche(): Double + oberFlaeche(): Double + mvolumen(): Double + compareVolumenTo(Prisma p): Integer RegelmaessigesPrisma # seite: Double Wuerfel + inhaltGrundflaeche(): Double + umfangGrundflaeche(): Double RegelmaessigesDreiecksPrisma + inhaltGrundflaeche(): Double + umfangGrundflaeche(): Double QuadratischerQuader + inhaltGrundflaeche(): Double + umfangGrundflaeche(): Double Quader − laenge: Double − breite: Double + inhaltGrundflaeche(): Double + umfangGrundflaeche(): Double Zylinder − radius: Double + inhaltGrundflaeche(): Double + umfangGrundflaeche(): Double RegelmaessigesSechsecksPrisma + inhaltGrundflaeche(): Double + umfangGrundflaeche(): Double b) Die Klasse Prisma lautet dann: abstract public class Prisma { // Gemeinsames Attribut aller Prismen ist die Hoehe: protected double hoehe; // Konstruktor: public Prisma (double h) { hoehe = h; } // Die Operationen umfangGrundflaeche() und inhaltGrundflaeche() // sind abhaengig von der Form des konkreten Prismas und koennen // hier nur abstrakt definiert werden: Lösung 8/ Seite 2 abstract public double umfangGrundflaeche(); abstract public double inhaltGrundflaeche(); // Die anderen Operationen koennen bereits in dieser Klasse implementiert // werden: // ....... } die Klasse Regelmaessiges Prisma: abstract public class RegelmaessigesPrisma extends Prisma { // alle Grundflaechen regelmaessiger Prismen sind gleichseitige // Vielecke. Als zusaetzliches Attribut genuegt die Seitenlaenge: protected double seite; // Konstruktor: public RegelmaessigesPrisma(double h, double s) { super(h); seite = s; } } Aufgabe 24 Telefonbäume (Lösungsvorschlag) a) Ein UML-Diagramm zur Beschreibung der erforderlichen Klassen, könnte folgendes Aussehen haben: Node PhoneTree tree + main() + getName() + insert() 10 followingNumbers + isLeaf() + getName() NameNode NumberNode − name: String + isLeaf() + getName() b) Telefonnummern: • int: max 10 Stellen; keine führende 0 erlaubt + isLeaf() + getName() + insert() Lösung 8/ Seite 3 • long: mehr Stellen; auch keine führende 0 erlaubt; nicht als Feldindex verwendtbar (cast notwendig) • String: viele Stellen inklusive führender 0; extrahieren einer Ziffer mittels number.charAt(position) - ’0’ liefert ASCII-Wert zwischen 0 und 9, der als Feldindex verwendtbar ist Der detaillierte Entwurf hat demzufolge folgendes Aussehen: Node PhoneTree + main(args : String[]) + getName(number : String) + insert(number : String, name : String) tree + isLeaf() + getName(number : String, position : Integer) + insert(number : String, position : Integer, name: String) 10 followingNumbers NameNode − name: String + isLeaf() + getName(number : String, position : Integer) + insert(number : String, position : Integer, name: String) NumberNode + isLeaf() + getName(number : String, position : Integer) + insert(number : String, position : Integer, name: String) c) Die Implementierung der verschiedenen Klassen lautet: abstract public class Node { abstract public boolean isLeaf(); abstract public String getName(String number, int position); abstract public void insert(String number, int position, String name); } public class NameNode extends Node { private String name; public NameNode(String name) { this.name = name; } public boolean isLeaf() { return true; } // liefert den gespeicherten Namen zurück public String getName(String number, int position) { Lösung 8/ Seite 4 return name + " (" + number.substring(0, position) + ")"; } // überschreibt den Namen public void insert(String number, int position, String name) { this.name = name; } } public class NumberNode extends Node { private Node[] followingNumbers = new Node[10]; public boolean isLeaf() { return false; } // Einfügen von eines Namens unter einer Nummer // zusätzlich zu Nummer und Name wird angegeben, welche Position // innerhalb der Telefonnummer gerade betrachtet wird public void insert(String number, int position, String name) { int index = getDigit(number, position); // index bestimmen if (index < 0 || 9 < index) return; // Fehler in number if (position + 1 == number.length()) { // Blatt mit Namen einfügen if (followingNumbers[index] != null && followingNumbers[index].isLeaf()) // verwende Blatt, falls vorhanden followingNumbers[index].insert(number, position, name); else // neues Blatt followingNumbers[index] = new NameNode(name); } else { // innerer Knoten if (followingNumbers[index] == null || followingNumbers[index].isLeaf()) { // Knoten neu anlegen falls notwendig followingNumbers[index] = new NumberNode(); } // rekursiv einfügen followingNumbers[index].insert(number, position + 1, name); } } // liefert Namen zu Nummer // auch hier wird angegeben, welche Position // innerhalb der Telefonnummer gerade betrachtet wird public String getName(String number, int position) { // index bestimmen int index = getDigit(number, position); if (index != -1 && followingNumbers[index] != null) { // rekursiv suchen return followingNumbers[index].getName(number, position + 1); } else { // nicht enhalten Lösung 8/ Seite 5 return "[unbekannte Nummer: " + number + "]"; } } // Hilfsfunktion zum Extrahieren einer Ziffer aus number an Position position // ganz einfach ohne Fehlerbehandlung private static int getDigit(String number, int position) { return number.charAt(position) - ’0’; } } public class PhoneTree { private NumberNode tree = new NumberNode(); public void insert(String number, String name) { System.out.println("einfügen von " + number + " " + name); tree.insert(number, 0,name); } public String getName(String number) { return "suche nach " + number + " ergab " + tree.getName(number,0); } public static void main(String[] args) { PhoneTree phoneTree = new PhoneTree(); phoneTree.insert("028918157", "Sekretäriat Seidl"); phoneTree.insert("028918161", "Fax Seidl"); phoneTree.insert("02890", "Uni"); System.out.println(phoneTree.getName("028918157")); System.out.println(phoneTree.getName("028918161")); System.out.println(phoneTree.getName("028918160")); System.out.println(phoneTree.getName("02890")); phoneTree.insert("028918161", "Fax2 Seidl"); System.out.println(phoneTree.getName("028918161")); phoneTree.insert("0289", "Uni Vorwahl"); System.out.println(phoneTree.getName("028918161")); } }