8 Baum in perfekter Komposition

Werbung
8 Baum in perfekter Komposition
8 Baum in perfekter Komposition
Die Implementierung des Binärbaums im letzten Kapitel wird mithilfe des Entwurfsmusters Kompositum optimiert.
Knoten und Abschluss
Bei der einfach verketteten Liste wurde durch den Einsatz des Entwurfsmusters Kompositum die Struktur der Klassenbeziehungen verändert und eine optimierte Implementierung erreicht.
4
Wie funktioniert das Software-Entwurfsmuster bei der einfach verketteten Liste? Welche
Sonderfälle vereinfacht es? Wie kann das Entwurfsmuster Kompositum bei Baumstrukturen angewendet werden? Welche Klassen benötigt man zur Umsetzung der Datenstruktur Binärbaum mithilfe des Entwurfsmusters Kompositum? In welchen Beziehungen
stehen die Klassen zueinander?
Jeder Knoten hat die Referenzattribute linkerNachfolger und rechterNachfolger. Gibt es keinen Nachfolger, so
hat das Referenzattribut den Wert
null.
In Abbildung 1 wurden, im Gegensatz
zu den vereinfachten Darstellungen
im letzten Kapitel, bei jedem Knoten
beide Pfeile als Symbol für die Referenzattribute eingetragen.
1 Darstellung des Binärbaums mit Abschlusssymbolen
Wie im Kapitel 4 ist auch hier der
Ansatz möglich, dass man anstelle von
null als Wert der Referenzattribute für
den linken und rechten Nachfolger
eine Referenz auf ein Objekt der Klasse ABSCHLUSS setzt. Objekte der
Klasse ABSCHLUSS haben weder
Referenzattribute auf Nachfolger
noch auf ein Datenelement, bieten
jedoch die gleiche Schnittstelle in
Form von Methoden an wie die Klasse KNOTEN.
In Abbildung 2 sind die Objekte der
Klasse ABSCHLUSS eingefügt.
2 Baum mit Objekten der Klasse ABSCHLUSS (blaue Einfärbung)
Objekte der Klassen KNOTEN und ABSCHLUSS müssen nach außen die gleichen Methoden anbieten, somit die gleiche Schnittstelle realisieren. Im Vergleich zur Liste wird diese
jedoch nicht LISTENELEMENT, sondern BAUMELEMENT genannt. Sowohl jeder Knoten
als auch jedes Abschluss-Objekt ist ein Baumelement. Deshalb wird die Schnittstelle durch
75
II Die rekursive Datenstruktur Baum
eine abstrakte Oberklasse realisiert. Das Klassendiagramm in
Abbildung 3 gibt eine Übersicht
über die beteiligten Klassen und
deren Beziehungen. Das Entwurfsmuster Kompositum ist
durch eine blaue Linienfarbe hervorgehoben.
3 Klassendiagramm der Binärbaumstruktur
mit Kompositum
Wie unterscheiden sich die Beziehungen des Klassendiagramms in Abbildung 3 von denen
im Klassendiagramm, das in Abbildung 3 von Kapitel 4 die Datenstruktur Liste mithilfe
des Entwurfsmusters Kompositum umsetzt?
Welche Änderungen ergeben sich bei den Attributen der Klassen KNOTEN, BINBAUM
und DATENELEMENT durch die Umstellung auf das Entwurfsmuster Kompositum?
Implementierung des Entwurfsmusters Kompositum – Attribute und Konstruktoren
BAUMELEMENT
{abstrakt}
Im ersten Schritt der Umsetzung werden nur die Attribute und Konstruktoren betrachtet.
Die Klasse BAUMELEMENT hat keine Attribute. Somit müssen im Konstruktor keine
BAUMELEMENT()
Anweisungen ausgeführt werden, der Rumpf ist leer.
ABSCHLUSS
Die Klasse ABSCHLUSS hat keine Attribute. Wiederum müssen im Konstruktor keine
Anweisungen ausgeführt werden. Im Sinne eines guten Programmierstils ruft man denABSCHLUSS()
noch den Konstruktor der Oberklasse auf.
BINBAUM
Die Klasse KNOTEN hat wie bisher Referenzen auf den rechten und linken Nachfolger
und ein Datenelement. Die Nachfolger sind entsprechend dem Klassendiagramm aus
BAUMELELEMNT wurzel
Abbildung 3 vom Datentyp BAUMELEMENT.
BINBAUM()
Der Konstruktor hat bisher beim Aufruf die eingegebene Referenz dem Referenzattribut
daten zugewiesen und die Werte der beiden Nachfolgerreferenzen auf null
KNOTEN
gesetzt. Letzteres muss geändert werden: Man muss zwei Objekte der KlasDATENELEMENT daten
se ABSCHLUSS erzeugen und deren Referenzen den Referenzattributen linBAUMELEMENT linkerNachfolger
kerNachfolger und rechterNachfolger zuordnen (Abbildung 4).
BAUMELEMENT rechterNachfolger
Die Klasse BINBAUM hat wie bisher ein Referenzattribut wurzel. Dieses ist
KNOTEN(DATENELEMENT)
nun vom Typ BAUMELEMENT. Beim Erzeugen eines leeren Baums ist die
KNOTEN(DATENELEMENT, KNOTEN, KNOTEN)
Wurzel ein Objekt der Klasse ABSCHLUSS (Abbildung 5).
4 Alle beteiligten Objekte beim Erzeugen eines Knotens
5 Alle beteiligten Objekte beim Erzeugen eines
Binärbaums
76
8 Baum in perfekter Komposition
Suchen …
Bei der Methode Suchen zeigt sich klar der Vorteil des Entwurfsmusters Kompositum. Alle
bedingten Anweisungen, die prüfen, ob es einen Nachfolger gibt oder nicht, werden
überflüssig. Dafür sind die Implementierungen der Methode Suchen in den Klassen
ABSCHLUSS und KNOTEN unterschiedlich.
- Suchen der Klasse KNOTEN:
War die Suche bisher erfolglos, so wird bei einem der Nachfolger ein rekursiver Aufruf
der Methode vorgenommen. Jeder Knoten hat jetzt immer zwei Nachfolger.
- Suchen der Klasse ABSCHLUSS:
Die Suche war erfolglos, es wird die leere Referenz zurückgegeben.
Folgende Gegenüberstellung zeigt die Änderungen im Detail:
vorher (einfacher Binärbaum)
nachher (Binärbaum nach Entwurfsmuster Kompositum)
Klasse KNOTEN
Methode
DATENELEMENT Suchen(String suchSchluessel)
Klasse KNOTEN
Methode
DATENELEMENT Suchen(String suchSchluessel)
wenn (daten.IstSchluesselGleich(suchSchluessel))
dann
return daten
sonst
wenn (daten.
IstSchluesselGroesserAls(suchSchluessel))
dann
wenn (linkerNachfolger != null)
dann
return linkerNachfolger.
Suchen(suchSchluessel)
sonst
return null
endewenn
sonst
wenn (rechterNachfolger != null)
dann
return rechterNachfolger.
Suchen(suchSchluessel)
sonst
return null
endewenn
endewenn
endewenn
wenn (daten.IstSchluesselGleich(suchSchluessel))
dann
return daten
sonst
wenn (daten.
IstSchluesselGroesserAls(suchSchluessel))
dann
return linkerNachfolger.
Suchen(suchSchluessel)
sonst
return rechterNachfolger.
Suchen(suchSchluessel)
endewenn
endewenn
Klasse ABSCHLUSS
Methode
DATENELEMENT Suchen(String suchSchluessel)
return null
6 Veränderung der Methode Suchen in der Klasse KNOTEN durch die Umstellung auf das Entwurfsmuster Kompositum
Die Methode Suchen der Klasse BINBAUM verkürzt sich ebenfalls. Es muss nicht mehr
überprüft werden, ob der Baum leer ist, denn ein leerer Baum hat ein Abschluss-Objekt.
Dieser gibt mit null die richtige Antwort auf eine Suchanfrage (siehe nächste Seite).
77
II Die rekursive Datenstruktur Baum
vorher (einfacher Binärbaum)
nachher (Binärbaum nach Entwurfsmuster Kompositum)
Klasse BINBAUM
Methode
DATENELEMENT Suchen(String suchSchluessel)
Klasse BINBAUM
Methode
DATENELEMENT Suchen(String suchSchluessel)
wenn (wurzel != null)
dann
return wurzel.Suchen(suchSchluessel)
sonst
return null
endewenn
return wurzel.Suchen(suchSchluessel)
7 Veränderung der Methode Suchen in der Klasse BINBAUM
durch die Umstellung auf das Entwurfsmuster Kompositum
… und Einfügen
Ein Einfügen findet beim geordneten Binärbaum immer am Ende eines Astes statt. Dort
wird das Abschluss-Objekt ersetzt durch einen neuen Knoten. Er referenziert das einzufügende Datenelement und zwei Objekte der Klasse ABSCHLUSS. Abbildung 8 verdeutlicht dies am Beispiel des Methodenaufrufs wurzel.Einfuegen(Referenz auf Datenelement mit
"cake" als Schlüssel). Der Abschluss a1 wird also durch einen neuen Knoten ersetzt, dessen Datenelement den Schlüssel "cake" hat und der zwei neue Abschlüsse referenziert.
8 Beim Einfügen wird ein Abschluss-Objekt (hier a1) durch einen neuen Knoten (hier mit der
Beschriftung „cake“) mit zwei neuen Abschluss-Objekten (hier a4 und a5) ersetzt.
Die Schwierigkeit bei dem in Abbildung 8 dargestellten Einfügevorgang ist, dass das
Objekt "call" noch nicht weiß, dass es einen neuen linken Nachfolger erhalten wird, wenn
es den Auftrag zum Einfügen an das Objekt a1 weitergibt. Das Objekt a1 erzeugt nun
einen neuen Knoten "cake". Da a1 seinen Aufrufer, das Objekt "call", bisher aber nicht
kennt, kann es ihn nicht über den neuen Nachfolger informieren.
Wie kann der Aufrufer trotz der fehlenden Referenz nach oben die Information über den
neuen Nachfolger erhalten?
Man löst dieses Problem, indem man die Methode Einfuegen mit einem Rückgabewert
vom Typ BAUMELEMENT versieht. Darüber kann jedes Objekt der Klasse ABSCHLUSS
(hier das Objekt a1) dem Aufrufer-Objekt (hier der Knoten mit der Beschriftung "call")
eine Referenz des von ihm erzeugten Knotens (hier der Knoten "cake") übergeben.
Welchen Wert geben Objekte der Klasse KNOTEN beim Aufruf der Methode Einfuegen
zurück?
78
8 Baum in perfekter Komposition
Objekte der Klasse KNOTEN rufen zwar abhängig davon, ob das eigene Datenelement
größer oder kleiner ist als die neuen Daten, die Methode Einfügen des linken oder rechten Nachbarn auf. Danach wird aber in beiden Fällen mit this die Referenz auf sich selbst
zurückgegeben, da die Position jedes Knotens innerhalb der Baumstruktur gleich bleibt.
Hinweise:
- Das Verfahren, eine Information an den Aufrufer einer Methode durch die Einführung
eines Rückgabewerts zu übergeben, wurde bereits bei der Methode EinfuegenVor bei
Listen und bei der Methode Entfernen bei Bäumen angewandt.
- Das Abschluss-Objekt a1 wird nach dem Einfügen (Abbildung 8 rechts) nicht mehr
benötigt. In den meisten objektorientierten Programmiersprachen werden nicht mehr
referenzierte Objekte von der U automatischen Speicherplatzbereinigung gelöscht.
3
7
U garbage collection
Der Ablauf beim Einfügen des Wortes „cake“:
wurzel.Einfuegen("cake")
Daten sind gleich? nein
Sind eigene Daten größer als die neuen Daten? ja
Beauftrage linken Nachfolger mit dem Einfügen.
wurzel.liNf.Einfuegen("cake")
Erzeuge einen Knoten mit einem Datenelement "cake".
Gib eine Referenz auf den erzeugten Knoten zurück.
Setze den Rückgabewert als linken Nachfolger.
Gib eine Referenz auf dich selbst zurück.
9 Ablauf des Methodenaufrufs wurzel.Einfuegen("cake")
79
Herunterladen