I Die rekursive Datenstruktur Liste 1 Einführung der Datenstruktur Schlange Aus dem Vorjahr ist das Feld vertraut als eine Datenstruktur, mit der mehrere gleichartige Objekte verwaltet werden können. In diesem Kapitel wird eine neue Datenstruktur vorgestellt, die in vielen Anwendungssituationen einfacher und besser geeignet ist. Die Klasse FELD In der etwas altmodischen Zahnarztpraxis von Frau Dr. Krankl mussten die Patienten bisher selbst darauf achten, wann sie an der Reihe waren. Dazu sollte sich der jeweils letzte Patient den Neuankömmling einprägen. Wenn der am längsten wartende Patient ins Behandlungszimmer gebeten wurde, informierte er die Arzthelfer, wen sie als Nächstes zur Behandlung rufen mussten. Diese Regelung führte aber immer wieder zu Missverständnissen. Aus diesem Grund sollen die Arzthelfer das Aufrufen der Patienten künftig mithilfe der EDV regeln. Sie sollen die neu hinzukommenden Patienten erfassen und den jeweils ersten Patienten auffordern, ins Behandlungszimmer zu gehen. Aus informatischer Sicht geht es hier um die Verwaltung vieler gleichartiger Objekte der Klasse PATIENT in einer Warteschlange. Dafür wurde im Vorjahr die Klasse FELD als Möglichkeit zur Realisierung der 1:n- Beziehung eingeführt. Mit einem Feld lässt sich beispielsweise eine Menge von Zahlen verwalten, ein Spielfeld fester Größe, auch zweidimensional, oder jede beliebige beschränkte Anzahl von Objekten einer bestimmten Klasse. letzte Patientin erster Patient Die zunächst naheliegende Problemlösung über ein Feld erweist sich jedoch aus mehreren Gründen als unbefriedigend: Durch die Länge des Feldes ist die maximale Anzahl der Elemente vorgegeben. Auch wenn man die Feldgröße sehr hoch wählt, ist man nicht davor gefeit, dass bei vielen eintreffenden Patienten der Speicherplatz irgendwann einmal nicht mehr ausreicht. Dann kann es zu Programmfehlern kommen (Abbildung 2, rechter Teil). Im Feld gibt es fast immer freie Plätze, die ohne Not Speicher verschwenden. Für das Aufrücken der Patienten und für das Einfügen neuer Patienten in das Feld sind komplexe Methoden erforderlich: Beim Aufrücken muss jeder Patient einzeln um jeweils eine Position nach vorne gerückt werden; beim Einfügen eines neuen Patienten muss das Feld so lange durchsucht werden, bis der erste freie Platz gefunden ist. Dabei legt das im Wartezimmer praktizierte Prinzip Hinten anstellen, vorne zum Arzt gehen eine einfachere Lösung nahe! 1 Von der Realität zum Objektdiagramm 5
I Die rekursive Datenstruktur Liste 2 Warteschlangenverwaltung mit Problem bei der Verwendung eines Feldes Exception in thread AWT-EventQueue-O java.lang.arrayindexoutofboundsexception: 5 at WARTESCHLANGE.Einfuegen(WARTESCHLANGE.java:15) Anforderungen an eine besser geeignete Datenstruktur Welche Eigenschaften soll eine Datenstruktur haben, die die oben beschriebenen Probleme nicht aufweist? Eine zur Realisierung des Wartezimmers besser geeignete Datenstruktur soll die folgenden Merkmale aufweisen: Die Anzahl der verwalteten Elemente soll prinzipiell unbeschränkt sein. Die Anzahl der reservierten, aber unbesetzten Speicherplätze soll möglichst gering sein. Optimal ist es, wenn es keinen unbesetzten Platz gibt. Da diese beiden Forderungen nicht durch einen vorab festgelegten Speicherumfang realisiert werden können, ist es notwendig, dass der Speicher zur Laufzeit dynamisch an die Erfordernisse angepasst wird. Die Umsetzung des Wartezimmers soll auf möglichst einfache Weise das Einfügen neuer Elemente am Ende und das Entfernen des vordersten Elements als Methoden bereitstellen. Weitere Aufgaben, wie der Zugriff auf Elemente in der Mitte der Wartezimmer- Datenstruktur, sind hier nicht erforderlich. Um die Reihenfolge der Elemente abzubilden, müssen die Elemente geeignet geordnet werden. Die Ordnung kann dadurch hergestellt werden, dass jedes Element seinen Nachfolger kennt. Die Beziehung zwischen einem Element und seinem Nachfolger bleibt auch erhalten, wenn weiter vorne ein Patient die Warteschlange verlässt. So lassen sich aufwendige Methoden zum Aufrücken, wie bei der Verwendung eines Feldes, vermeiden. Die Datenstruktur Schlange (auch: Warteschlange, Queue, Puffer), die nachfolgend vorgestellt wird, erfüllt genau diese Voraussetzungen. Schlangen werden vielfältig genutzt. Sie sind immer sinnvoll, wenn Erzeuger Aufträge geben, die von Verbrauchern abgearbeitet werden müssen. Ein Erzeuger legt einen Auftrag am Ende der Schlange ab. Auch wenn die Verbraucher den Auftrag noch nicht abgearbeitet haben, können neue Aufträge hinzugefügt werden. Die Verbraucher holen sich zu einem späteren Zeitpunkt die Aufträge der Reihe nach ab. Schlangen werden bei vielen Anwendungen verwendet: Die Verwaltung der Anrufer in einem Callcenter kann über die Datenstruktur Schlange realisiert werden. Von verschiedenen Programmen können Druckaufträge an eine Druckerwarteschlange gesendet werden. Der Druckertreiber, der die Interaktion mit dem Drucker regelt, holt dort die Aufträge der Reihe nach ab. Datenbankserver haben einen Puffer für Abfragen, die auf ihre Abarbeitung warten. 6
Modellierung der Schlange Welche Objekte werden in der neuen Datenstruktur benötigt? Welche Beziehungen bestehen zwischen ihnen? Wie lassen sich die Objekte klassifizieren? Bei Dr. Krankl besteht die Warteschlange aus Patienten. Jeder Patient trägt seine spezifischen Informationen. Im Beispiel soll dies nur der Name sein; in der Realität könnten hier viele weitere Patientendaten, wie die Krankenkasse oder gespeicherte Behandlungsdaten, hinzukommen. Jeder Patient merkt sich außerdem seinen Nachfolger. Die Arzthelfer greifen über die Warteschlange nur auf den ersten und den letzten Patienten zu. Im Objektdiagramm lassen sich diese Zusammenhänge folgendermaßen veranschaulichen: 3 Objektdiagramm der Warteschlange Die Warteschlange hat zwei Beziehungen zu Patienten: Sie verwaltet eine Referenz auf den ersten und auf den letzten Patienten. Ein Patient hat als Nachfolger keinen oder einen Patienten. Zwischen zwei Patienten gibt es also die hat als Nachfolger -Beziehung. Eine solche selbstbezügliche Beziehung nennt man rekursive Beziehung. Auf diese Weise kann eine beliebige und prinzipiell unbeschränkte Anzahl an Patienten verwaltet werden. Die Warteschlange bildet insgesamt eine rekursive Struktur. lat. recurrere: zurückkehren Nach Klärung des grundsätzlichen Aufbaus und des Zusammenhangs der Daten kann nun die Funktionalität über die Methoden genauer eingegrenzt werden: Die Warteschlange muss in der Lage sein, einen neuen Patienten hinten einzufügen sowie den vordersten Patienten zu entfernen und auszugeben, zum Beispiel zur Weiterleitung an den Arzt im Behandlungszimmer. Dafür benötigt die Klasse WARTESCHLANGE die Methoden Einfuegen und Entfernen. 4 Beziehungen im Klassendiagramm 5 Einfuegen und Entfernen von Patienten 7
I Die rekursive Datenstruktur Liste Ein Patient muss festlegen und ausgeben können, wer sein Nachfolger ist, damit klar ist, wer nach ihm an der Reihe ist. Die Klasse PATIENT muss dafür die Methoden NachfolgerSetzen und NachfolgerGeben bereitstellen. Da es manchmal erforderlich ist, nur den Namen des vordersten Patienten herauszufinden, ohne ihn schon aus der Liste zu entfernen, wird sowohl bei der Warteschlange als auch beim Patienten eine Methode InformationAusgeben benötigt. Damit lassen sich die Klassen mit ihren Beziehungen identifizieren und in einem ersten erweiterten Klassendiagramm veranschaulichen. 6 Klassendiagramm zur Warteschlange Implementierung der Schlange Zur Realisierung der Beziehungen zwischen Warteschlange und Patient benötigt man in der Klasse WARTESCHLANGE die Referenzattribute anfang und ende vom Typ PATIENT. In der Klasse PATIENT braucht man das Referenzattribut nachfolger des gleichen Typs zur Umsetzung der rekursiven Beziehung hat als Nachfolger. WARTESCHLANGE PATIENT anfang PATIENT ende WARTESCHLANGE() void Einfuegen(PATIENT) PATIENT Entfernen() void InformationAusgeben() PATIENT String name PATIENT nachfolger PATIENT(String) void NachfolgerSetzen(PATIENT) PATIENT NachfolgerGeben() void InformationAusgeben() 7 Erweiterte Klassendiagramme für WARTE- SCHLANGE und PATIENT Die verschiedenen Methoden der Klasse PATIENT sind einfach zu implementieren: Der Konstruktor PATIENT erwartet als Eingabe den Namen des Patienten, setzt das Attribut name auf den entsprechenden Wert und nachfolger auf null. Die Methode NachfolgerSetzen erhält als Parameter eine Referenz auf ein Objekt der Klasse PATIENT und weist diese Referenz dem Attribut nachfolger zu. Die Funktion NachfolgerGeben gibt den Wert des Referenzattributs nachfolger aus. InformationAusgeben sorgt für die Ausgabe des Wertes von name über ein Ausgabefenster. Die Methoden der Klasse WARTESCHLANGE lassen sich folgendermaßen beschreiben: Der Konstruktor erzeugt eine leere Warteschlange. Der Methode Einfuegen wird ein Patient übergeben. Zunächst muss für den Patienten, der bisher als ende geführt wurde, die Methode NachfolgerSetzen mit dem neuen Patienten aufgerufen werden. Danach kann der neue Patient als ende registriert werden. Dabei muss darauf geachtet werden, dass die Warteschlange zuvor nicht leer war. 8
Die Methode Entfernen gibt eine Referenz auf den ersten Patienten aus, damit ihn die Arzthelferin ansprechen kann. Außerdem wird vom ersten Patienten durch Aufruf von NachfolgerGeben der Nachfolger geholt; dieser wird als neuer anfang gesetzt. Auch hier muss darauf geachtet werden, dass die Warteschlange nicht leer ist. Die Methode InformationAusgeben der Klasse WARTESCHLANGE ruft ihrerseits die gleichnamige Methode des ersten Patienten auf. Wieder muss darauf geachtet werden, dass die Warteschlange nicht leer ist. Klasse WARTESCHLANGE Methode Einfuegen(PATIENT patientneu) wenn (ende!= null) ende.nachfolgersetzen(patientneu) sonst anfang = patientneu ende = patientneu 8 Pseudocode zu Einfuegen Klasse WARTESCHLANGE Methode PATIENT Entfernen() PATIENT p p = anfang wenn (anfang!= null) anfang = anfang.nachfolgergeben() wenn (anfang == null) ende = null return p 9 Pseudocode zu Entfernen Die Datenstruktur Schlange stellt eine Möglichkeit zur Realisierung einer 1:n-Beziehung mit unbeschränktem Wert für n dar. Über die Klasse WARTESCHLANGE ist das Einfügen von Elementen am Ende und das Entfernen am Anfang der Schlange möglich. Eine Beziehung zwischen Objekten der gleichen Klasse nennt man rekursive Beziehung. Zwischen den Elementen der Warteschlange besteht die rekursive Beziehung hat als Nachfolger. Zur Realisierung der Beziehung im Programm muss die Klasse der verwalteten Objekte ein Referenzattribut für den Nachfolger bereitstellen. Dadurch werden die Objekte verkettet. Aufgaben 1 Grundwissen Beziehungen a Erläutern Sie an selbst gewählten Beispielen: Wie können Beziehungen zwischen Objekten realisiert werden? In welchen Fällen eignet sich dabei die Klasse FELD? b Welche Syntax stellt die von Ihnen verwendete Programmiersprache für die Umsetzung von Beziehungen durch Referenzattribute oder Felder zur Verfügung? 2 Feld oder Schlange was ist besser? a Die Patientenverwaltung in einer Arztpraxis kann über ein Feld oder über eine Schlange erfolgen. Erörtern Sie Vor- und Nachteile der beiden Lösungsansätze. Entscheiden und begründen Sie bei den folgenden vier Teilaufgaben, ob ein Feld oder eine Schlange für die Problemlösung besser geeignet ist. b System zur Festlegung der Startreihenfolge bei einem Ski-Weltcuplauf c System zur Erfassung der Ergebnisse bei einem Ski-Weltcuplauf 9