Abitur NRW Informatik 2021 · GK · Haupttermin

Abiturprüfung Informatik in Nordrhein-Westfalen 2021, GK · Haupttermin: 11 Aufgaben mit Lösungen. Mit automatischer Korrektur.

Themen der Prüfung: Objektorientierte Modellierung mit Implementationsdiagrammen · Algorithmen auf Feldern und linearen Listen · Binärbäume und binäre Suchbäume · Datenbankmodellierung und Normalisierung · SQL-Abfragen · Endliche Automaten · Grammatiken, Kellerautomaten und Grenzen endlicher Automaten · Datenschutz und Datensicherheit

Aufgabe 1 - Objektorientierte Modellierung mit Im… · Objektorientierte Modellierung mit Implementationsdiagrammen

Aufgabenstellung:

Ein Projektkurs zum Thema „Klimawandel“ plant, eine Software zu entwickeln, mit der Wetterdaten verwaltet und ausgewertet werden können.

Der Kurs verfügt über Daten von Wetterstationen aus ganz Deutschland, jeweils mit eindeutigem Stationsnamen und zugehöriger Stadt. Abhängig von ihrer Ausstattung erfasst jede Wetterstation unterschiedliche Messwertarten (z. B. die Temperatur in °C oder die Windgeschwindigkeit in km/h). Zu jeder Messung werden Messwertart, Messwert und Zeitpunkt abgelegt (vgl. Abbildung 1).

Das folgende Implementationsdiagramm zeigt einen ersten Modellierungsentwurf zur Verwaltung der Wetterdaten. Die Klassendokumentationen stehen im Anhang.

Anhang: Dokumentationen der verwendeten Klassen

Die Klasse Wetterdatenverwaltung

Objekte der Klasse Wetterdatenverwaltung verwalten Wetterstationen mit ihren Messungen.

Auszug aus der Dokumentation der Klasse Wetterdatenverwaltung

Wetterdatenverwaltung()

Ein Objekt der Klasse Wetterdatenverwaltung wird initialisiert.

List<Wetterstation> gibWetterstationen()

Eine Liste mit allen Wetterstationen wird zurückgeliefert.

Wetterstation gibWetterstation(String pStationsname)

Die Wetterstation mit dem Namen pStationsname wird zurückgeliefert. Wenn zu diesem Namen keine Wetterstation existiert, dann wird null zurückgeliefert.

void fuegeHinzu(Wetterstation pWetterstation)

Die Wetterstation pWetterstation wird der Wetterdatenverwaltung hinzugefügt, wenn der Stationsname bisher noch nicht existiert. Sonst geschieht nichts.

void fuegeHinzu(Wetterstation pWetterstation, Messung pMessung)

Wenn die Wetterstation pWetterstation in der Wetterdatenverwaltung existiert, dann wird dieser Station die Messung pMessung hinzugefügt. Sonst geschieht nichts.

Double ermittleEtwas(String pMesswertart, int pJahr)

Diese Methode soll in Teilaufgabe b) analysiert werden.

Die Klasse Wetterstation

Objekte der Klasse Wetterstation verwalten ihren Stationsnamen, ihre Stadt und ihre Messungen.

Auszug aus der Dokumentation der Klasse Wetterstation

Wetterstation(String pStationsname, String pStadt)

Ein Objekt der Klasse Wetterstation wird mit dem Stationsnamen pStationsname und der Stadt pStadt initialisiert.

String gibStationsname()

Der Stationsname wird zurückgeliefert.

String gibStadt()

Die Stadt wird zurückgeliefert.

List<Messung> gibMessungen()

Eine Liste mit allen Messungen dieser Wetterstation wird zurückgeliefert.

void fuegeHinzu(Messung pMessung)

Die Messung pMessung wird hinzugefügt.

Double ermittleMaximum(String pMesswertart)

Für die im Parameter übergebene Messwertart pMesswertart wird der höchste dokumentierte Messwert der jeweiligen Wetterstation ermittelt. Wenn für die Wetterstation kein Messwert dieser Messwertart vorliegt, dann soll null zurückgeliefert werden.

Diese Methode soll in Teilaufgabe c) hinzugefügt werden.

Die Klasse Messung

Objekte der Klasse Messung verwalten ihre Messwertart, ihren Messwert und ihren Zeitpunkt.

Auszug aus der Dokumentation der Klasse Messung

Messung(String pMesswertart, double pMesswert, int pJahr, int pMonat, int pTag, int pStunde, int pMinute)

Ein Objekt der Klasse Messung wird mit der Messwertart pMesswertart, dem Messwert pMesswert und dem Zeitpunkt der Messung initialisiert.

String gibMesswertart()

Die Messwertart wird zurückgeliefert.

double gibMesswert()

Der Messwert wird zurückgeliefert.

int gibJahr()

Das Jahr wird zurückgeliefert.

int gibMonat()

Der Monat wird zurückgeliefert.

int gibTag()

Der Tag wird zurückgeliefert.

int gibStunde()

Die Stunde wird zurückgeliefert.

int gibMinute()

Die Minute wird zurückgeliefert.

Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden.

Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List()

Eine leere Liste wird erzeugt.

boolean isEmpty()

Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess()

Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next()

Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst()

Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast()

Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls ( hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent)

Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt ( hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt ( hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt ( hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList)

Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr ( hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt ( hasAccess() == false), bleibt die Liste unverändert.

Die Klasse Double

Ein Objekt der Klasse Double verwaltet als Inhalt eine Dezimalzahl.

Auszug aus der Dokumentation der Klasse Double

Double(double value)

Ein Objekt der Klasse Double wird mit dem Inhalt value initialisiert.

double doubleValue()

Liefert den double-Wert dieses Double-Objektes zurück.

a)

Beschreiben Sie, in welchen Beziehungen die Klassen der in Abbildung 2 dargestellten Teilmodellierung zueinander stehen.

Begründen Sie im Sachkontext, weshalb es zweckmäßig ist, die Wetterstationen und die Messungen jeweils in einer linearen Liste statt in einem Feld (Array) zu speichern. (5 Punkte)

d)

Der erste Prototyp der Software wurde getestet. Dabei zeigt sich, dass das Projekt ausgebaut werden muss, damit es wirklich aussagekräftige Ergebnisse liefert. Zusätzlich sollen die folgenden Anforderungen umgesetzt werden:

i. Die Wetterdatenverwaltung soll – für eine bestimmte Messwertart – den kleinsten Messwert zurückliefern können.

ii. Um möglichst schnell zu jeder Messung die zugehörige Wetterstation ermitteln zu können, soll eine Messung auch Kenntnis über ihre Wetterstation haben. Eine Messung soll ihre Wetterstation auch zurückliefern können.

iii. Der Projektkurs möchte in Zukunft auch mobile Messungen durchführen können, z. B. mit Wetterballons oder Treibbojen. Eine mobile Messung soll weiterhin einer Wetterstation zugeordnet sein. Zusätzlich soll nur für jede mobile Messung ihre Position in Form von zwei Werten gespeichert werden (z. B. 51.955013, 7.611646). Beide Werte sollen auch abgerufen werden können.

Modellieren Sie die zuvor genannten Anforderungen, indem Sie das Implementationsdiagramm aus Abbildung 2 erweitern.

Erläutern Sie, auf welche Weise die zweite und die dritte Anforderung in Ihrem Implementationsdiagramm umgesetzt sind.

Hinweis: Klassen, Methoden und Attribute aus Abbildung 2, die sich nicht ändern, brauchen nicht erneut dargestellt oder angegeben zu werden. (13 Punkte)

e)

Ein Schüler regt an, die Klassen Wetterstation und Messung durch eine neue Klasse Wetteraufzeichnung zu ersetzen. Beispieldaten für Wetteraufzeichnungen sind im Folgenden aufgeführt:

Stationsname

Stadt

Messwertart

Messwert

Zeitpunkt

Botanischer Garten · Berlin · Temperatur · 17.0 · 2020-08-04 09:01

Botanischer Garten · Berlin · Temperatur · 18.4 · 2020-08-04 10:02

Botanischer Garten · Berlin · Temperatur · 20.6 · 2020-08-04 12:07

Leuchtturm · Kiel · Windgeschwindigkeit · 2.0 · 2019-08-03 10:02

Leuchtturm · Kiel · Windgeschwindigkeit · 20.0 · 2019-12-31 12:07

Zugspitze · Garmisch-Partenkirchen · Temperatur · -10.3 · 2019-12-31 09:01

Zugspitze · Garmisch-Partenkirchen · Windgeschwindigkeit · 20.0 · 2019-12-31 09:01

Zugspitze · Garmisch-Partenkirchen · Temperatur · 4.0 · 2020-08-04 13:01

Zugspitze · Garmisch-Partenkirchen · Windgeschwindigkeit · 32.0 · 2020-08-04 13:01

Teststation · Soest

Abbildung 3: Beispieldaten für Wetteraufzeichnungen

Die Klasse Wetterdatenverwaltung hätte dann eine Liste mit Objekten der Klasse Wetteraufzeichnung zu verwalten.

Nach Aussage des Schülers lassen sich aus dieser einen Liste von Wetteraufzeichnungen ohnehin alle Informationen entnehmen; zudem sei sein Vorschlag leichter zu implementieren und habe sonst keine nennenswerten Nachteile.

Begründen Sie ausgehend von der Behauptung des Schülers, weshalb der Alternativvorschlag abzulehnen ist. (7 Punkte)

Aufgabe 1 - Algorithmen auf Feldern und linearen… · Algorithmen auf Feldern und linearen Listen

Aufgabenstellung:

Ein Projektkurs zum Thema „Klimawandel“ plant, eine Software zu entwickeln, mit der Wetterdaten verwaltet und ausgewertet werden können.

Der Kurs verfügt über Daten von Wetterstationen aus ganz Deutschland, jeweils mit eindeutigem Stationsnamen und zugehöriger Stadt. Abhängig von ihrer Ausstattung erfasst jede Wetterstation unterschiedliche Messwertarten (z. B. die Temperatur in °C oder die Windgeschwindigkeit in km/h). Zu jeder Messung werden Messwertart, Messwert und Zeitpunkt abgelegt (vgl. Abbildung 1).

Das folgende Implementationsdiagramm zeigt einen ersten Modellierungsentwurf zur Verwaltung der Wetterdaten. Die Klassendokumentationen stehen im Anhang.

Anhang: Dokumentationen der verwendeten Klassen

Die Klasse Wetterdatenverwaltung

Objekte der Klasse Wetterdatenverwaltung verwalten Wetterstationen mit ihren Messungen.

Auszug aus der Dokumentation der Klasse Wetterdatenverwaltung

Wetterdatenverwaltung()

Ein Objekt der Klasse Wetterdatenverwaltung wird initialisiert.

List<Wetterstation> gibWetterstationen()

Eine Liste mit allen Wetterstationen wird zurückgeliefert.

Wetterstation gibWetterstation(String pStationsname)

Die Wetterstation mit dem Namen pStationsname wird zurückgeliefert. Wenn zu diesem Namen keine Wetterstation existiert, dann wird null zurückgeliefert.

void fuegeHinzu(Wetterstation pWetterstation)

Die Wetterstation pWetterstation wird der Wetterdatenverwaltung hinzugefügt, wenn der Stationsname bisher noch nicht existiert. Sonst geschieht nichts.

void fuegeHinzu(Wetterstation pWetterstation, Messung pMessung)

Wenn die Wetterstation pWetterstation in der Wetterdatenverwaltung existiert, dann wird dieser Station die Messung pMessung hinzugefügt. Sonst geschieht nichts.

Double ermittleEtwas(String pMesswertart, int pJahr)

Diese Methode soll in Teilaufgabe b) analysiert werden.

Die Klasse Wetterstation

Objekte der Klasse Wetterstation verwalten ihren Stationsnamen, ihre Stadt und ihre Messungen.

Auszug aus der Dokumentation der Klasse Wetterstation

Wetterstation(String pStationsname, String pStadt)

Ein Objekt der Klasse Wetterstation wird mit dem Stationsnamen pStationsname und der Stadt pStadt initialisiert.

String gibStationsname()

Der Stationsname wird zurückgeliefert.

String gibStadt()

Die Stadt wird zurückgeliefert.

List<Messung> gibMessungen()

Eine Liste mit allen Messungen dieser Wetterstation wird zurückgeliefert.

void fuegeHinzu(Messung pMessung)

Die Messung pMessung wird hinzugefügt.

Double ermittleMaximum(String pMesswertart)

Für die im Parameter übergebene Messwertart pMesswertart wird der höchste dokumentierte Messwert der jeweiligen Wetterstation ermittelt. Wenn für die Wetterstation kein Messwert dieser Messwertart vorliegt, dann soll null zurückgeliefert werden.

Diese Methode soll in Teilaufgabe c) hinzugefügt werden.

Die Klasse Messung

Objekte der Klasse Messung verwalten ihre Messwertart, ihren Messwert und ihren Zeitpunkt.

Auszug aus der Dokumentation der Klasse Messung

Messung(String pMesswertart, double pMesswert, int pJahr, int pMonat, int pTag, int pStunde, int pMinute)

Ein Objekt der Klasse Messung wird mit der Messwertart pMesswertart, dem Messwert pMesswert und dem Zeitpunkt der Messung initialisiert.

String gibMesswertart()

Die Messwertart wird zurückgeliefert.

double gibMesswert()

Der Messwert wird zurückgeliefert.

int gibJahr()

Das Jahr wird zurückgeliefert.

int gibMonat()

Der Monat wird zurückgeliefert.

int gibTag()

Der Tag wird zurückgeliefert.

int gibStunde()

Die Stunde wird zurückgeliefert.

int gibMinute()

Die Minute wird zurückgeliefert.

Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden.

Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List()

Eine leere Liste wird erzeugt.

boolean isEmpty()

Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess()

Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next()

Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst()

Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast()

Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls ( hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent)

Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt ( hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt ( hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt ( hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList)

Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr ( hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt ( hasAccess() == false), bleibt die Liste unverändert.

Die Klasse Double

Ein Objekt der Klasse Double verwaltet als Inhalt eine Dezimalzahl.

Auszug aus der Dokumentation der Klasse Double

Double(double value)

Ein Objekt der Klasse Double wird mit dem Inhalt value initialisiert.

double doubleValue()

Liefert den double-Wert dieses Double-Objektes zurück.

Teilaufgabe b)

Das Projekt ist bereits weit fortgeschritten, als eine Schülerin in der Klasse Wetterdatenverwaltung auf die nicht dokumentierte Methode ermittleEtwas stößt:

public Double ermittleEtwas(String pMesswertart,

int pJahr) {

Double wert = null;

double summe = 0;

int anzahl = 0;

wetterstationen.toFirst();

while (wetterstationen.hasAccess()) {

Wetterstation station = wetterstationen.getContent();

List<Messung> messungen = station.gibMessungen();

messungen.toFirst();

while (messungen.hasAccess()) {

Messung m = messungen.getContent();

if (m.gibJahr() == pJahr

&& m.gibMesswertart().equals(pMesswertart)) {

anzahl = anzahl + 1;

summe = summe + m.gibMesswert();

}

messungen.next();

}

wetterstationen.next();

}

if (anzahl > 0) {

wert = new Double(summe / anzahl);

}

return wert;

} Analysieren Sie die Methode und geben Sie anhand der Beispieldaten aus Abbildung 1 an, welche Rückgabewerte die drei folgenden Methodenaufrufe liefern:

Begründen Sie, weshalb die Methode ein Double -Objekt statt eines Werts vom Typ double liefert.

Erläutern Sie, welchen Zweck die Methode im Sachzusammenhang erfüllt.

Teilaufgabe c)

In die Klasse Wetterstation soll die im Anhang dokumentierte Methode ermittleMaximum aufgenommen werden. Sie hat folgenden Methodenkopf:

public Double ermittleMaximum(String pMesswertart) Entwickeln und erläutern Sie für diese Methode ein algorithmisches Verfahren.

Implementieren Sie die Methode.

Aufgabe 2 - Objektorientierte Modellierung mit Im… · Objektorientierte Modellierung mit Implementationsdiagrammen

Ein neu gegründetes Startup in Köln vermietet Elektro-Roller (Scooter). Jeder Scooter besitzt einen GPS-Empfänger und sendet per Internetverbindung jede Minute seine aktuelle Position (Standort) und seinen Batterie-Zustand (Akkuladung) an den Unternehmensserver. Damit sich der Abstand zur Firmenzentrale einfach bestimmen lässt, geben die Scooter ihre Position relativ zur Firmenzentrale an (Koordinatenursprung). Auf dem Server wird die zuletzt gemeldete Position jeweils als Punkt in einem Koordinatensystem abgelegt. Abbildung 1 stellt die momentane Lage in der näheren Umgebung der Firmenzentrale dar.

Die Scooter werden im Unternehmen in einem binären Suchbaum verwaltet. Als Suchschlüssel im Baum dient die eindeutige vierstellige (Serien-)Nummer eines Scooters.

Aktuell setzt das Unternehmen die vier in Abbildung 1 gezeigten Scooter ein. Abbildung 2 zeigt den daraus entstehenden binären Suchbaum.

Die Software des Unternehmens verwaltet neben den Scooter-Daten auch die Daten der Kundinnen und Kunden, die Scooter ausleihen wollen. Vereinfachend wird jede Kundin und jeder Kunde in der Modellierung nur durch eine eindeutige E-Mail-Adresse und eine Kreditkartennummer für die Abrechnung beschrieben.

Grundlage der Software ist der in Abbildung 3 gezeigte Ausschnitt des Implementationsdiagramms.

Anhang: Dokumentationen der verwendeten Klassen

Die Klasse Scooter

Objekte dieser Klasse verwalten die Daten eines Scooters.

Methode · Beschreibung

Scooter(int pNummer) · Ein Objekt der Klasse wird initialisiert. Die eindeutige Nummer pNummer wird gespeichert.

boolean isEqual(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, gleich der Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isLess(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, kleiner als die Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isGreater(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, größer als die Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

int gibNummer() · Die Methode liefert die eindeutige Nummer des Scooters.

int gibAkkuladung() · Die Methode liefert den Batterie-Zustand des Scooters. Der Wert entspricht der Akkuladung in Prozent, d. h., der Wert liegt im Wertebereich 0 (Akku ist leer) bis 100 (Akku ist vollständig aufgeladen).

Kunde gibAusleiher() · Die Methode liefert das Objekt der Klasse Kunde, welcher den Scooter momentan ausgeliehen hat. Ist der Scooter momentan nicht verliehen, so wird null zurückgegeben.

Standort gibStandort() · Die Methode liefert ein Objekt der Klasse Standort, welches die Koordinaten relativ zur Firmenzentrale enthält. Z. B. bedeutet der Standort (-300|400), dass sich der Scooter 300 Meter in westlicher Richtung und 400 Meter in nördlicher Richtung von der Firmenzentrale befindet.

void setzeAkkuladung(int pAkkuladung) · Die Methode verändert den Wert der Akkuladung auf den Wert pAkkuladung. Ist der Wert kleiner als 0 oder größer als 100, so geschieht nichts.

void setzeAusleiher(Kunde pAusleiher) · Die Methode speichert die Daten der Person, die den Scooter momentan ausgeliehen hat. Ist der Parameter pAusleiher gleich null, so ist der Scooter wieder frei und kann von jemand anderem ausgeliehen werden.

void setzeStandort(Standort pStandort) · Die Methode setzt den Standort des Scooters auf pStandort.

Die Klasse ScooterVerwaltung

Objekte dieser Klasse verwalten Scooter sowie Kundinnen und Kunden und ermöglichen die Ausleihe von Scootern.

Methode · Beschreibung

ScooterVerwaltung() · Ein Objekt der Klasse wird initialisiert. Es verwaltet noch keine Scooter und keine Daten von Kundinnen und Kunden.

void ausleihen(String pEMailAdresse, int pScooternummer) · Die Person mit der E-Mail-Adresse pEMailAdresse leiht den Scooter mit der Nummer pScooternummer aus. Dazu speichert das zugehörige Objekt der Klasse Scooter eine Referenz auf das zugehörige Objekt der Klasse Kunde. Sollte keine Kundin und kein Kunde mit der E-Mail-Adresse pEMailAdresse bzw. kein Scooter mit der Nummer pScooternummer existieren, so geschieht nichts. Sollte der Scooter bereits ausgeliehen sein, so geschieht ebenfalls nichts.

Scooter gibScooter(int pScooternummer) · Liefert das Scooter-Objekt mit der (Serien-)Nummer pScooternummer. Falls es kein Scooter-Objekt mit der entsprechenden (Serien-)Nummer gibt, dann wird null zurückgeliefert.

List<Scooter> liefereEtwas(int pWert) · Die Methode wird in Teilaufgabe c) analysiert.

Die Klasse Kunde

Objekte dieser Klasse verwalten die Daten einer Kundin bzw. eines Kunden.

Methode · Beschreibung

Kunde(String pEMailAdresse, String pKreditkartennummer) · Ein Objekt der Klasse wird initialisiert. Die eindeutige E-Mail-Adresse pEMailAdresse der Kundin bzw. des Kunden und die zugehörige Kreditkartennummer pKreditkartennummer werden gespeichert.

String gibEMailAdresse() · Die eindeutige E-Mail-Adresse der Kundin bzw. des Kunden wird zurückgeliefert.

String gibKreditkartennummer() · Die Kreditkartennummer der Kundin bzw. des Kunden wird zurückgeliefert.

Die Klasse Standort

Objekte dieser Klasse verwalten die Koordinaten eines Standorts für Scooter. Die Koordinaten werden relativ zur Firmenzentrale gespeichert, welche sich im Koordinatenursprung befindet.

Methode · Beschreibung

Standort(int pX, int pY) · Ein Objekt der Klasse wird initialisiert. Die Koordinaten (pX|pY) werden im Objekt gespeichert.

int gibX() · Die x-Koordinate des Standorts wird zurückgeliefert. Diese entspricht der Entfernung in westlicher (bei negativem Wert) bzw. in östlicher (bei positivem Wert) Richtung in Metern von der Firmenzentrale.

int gibY() · Die y-Koordinate des Standorts wird zurückgeliefert. Diese entspricht der Entfernung in südlicher (bei negativem Wert) bzw. in nördlicher (bei positivem Wert) Richtung in Metern von der Firmenzentrale.

Die generische Klasse List<ContentType>

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden. Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Methode · Beschreibung

List() · Eine leere Liste wird erzeugt.

boolean isEmpty() · Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess() · Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next() · Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst() · Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast() · Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent() · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent) · Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent) · Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent) · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList) · Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove() · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.

Die generische Klasse BinarySearchTree<ContentType extends ComparableContent<ContentType>>

Mithilfe der generischen Klasse BinarySearchTree können beliebig viele Objekte des Typs ContentType in einem Binärbaum (binärer Suchbaum) entsprechend einer Ordnungsrelation verwaltet werden. Ein Objekt der Klasse BinarySearchTree stellt entweder einen leeren Baum dar oder verwaltet ein Inhaltsobjekt vom Typ ContentType sowie einen linken und einen rechten Teilbaum, die ebenfalls Objekte der Klasse BinarySearchTree sind. Die Klasse der Objekte, die in dem Suchbaum verwaltet werden sollen, muss das generische Interface ComparableContent implementieren. Dabei muss durch Überschreiben der drei Vergleichsmethoden isLess, isEqual, isGreater eine eindeutige Ordnungsrelation festgelegt sein.

Für je zwei Objekte c1 und c2 vom Typ ContentType gilt also insbesondere genau eine der drei Aussagen:

c1.isLess(c2) (Sprechweise: c1 ist kleiner als c2)

c1.isEqual(c2) (Sprechweise: c1 ist gleichgroß wie c2)

c1.isGreater(c2) (Sprechweise: c1 ist größer als c2)

Alle Objekte im linken Teilbaum sind kleiner als das Inhaltsobjekt des Binärbaumes. Alle Objekte im rechten Teilbaum sind größer als das Inhaltsobjekt des Binärbaumes. Diese Bedingung gilt auch in beiden Teilbäumen.

Methode · Beschreibung

BinarySearchTree() · Der Konstruktor erzeugt einen leeren Suchbaum.

boolean isEmpty() · Diese Anfrage liefert den Wahrheitswert true, wenn der Suchbaum leer ist, sonst liefert sie den Wert false.

void insert(ContentType pContent) · Falls bereits ein Objekt in dem Suchbaum vorhanden ist, das gleichgroß ist wie pContent, passiert nichts. Andernfalls wird das Objekt pContent entsprechend der Ordnungsrelation in den Baum eingeordnet. Falls der Parameter null ist, ändert sich nichts.

ContentType search(ContentType pContent) · Falls ein Objekt im binären Suchbaum enthalten ist, das gleichgroß ist wie pContent, liefert die Anfrage dieses, ansonsten wird null zurückgegeben. Falls der Parameter null ist, wird null zurückgegeben.

void remove(ContentType pContent) · Falls ein Objekt im binären Suchbaum enthalten ist, das gleichgroß ist wie pContent, wird dieses entfernt. Falls der Parameter null ist, ändert sich nichts.

ContentType getContent() · Diese Anfrage liefert das Inhaltsobjekt des Suchbaumes. Wenn der Suchbaum leer ist, wird null zurückgegeben.

BinarySearchTree<ContentType> getLeftTree() · Diese Anfrage liefert den linken Teilbaum des binären Suchbaumes. Der binäre Suchbaum ändert sich nicht. Wenn er leer ist, wird null zurückgegeben.

BinarySearchTree<ContentType> getRightTree() · Diese Anfrage liefert den rechten Teilbaum des Suchbaumes. Der Suchbaum ändert sich nicht. Wenn er leer ist, wird null zurückgegeben.

Das generische Interface ComparableContent<ContentType>

Das generische Interface ComparableContent muss von Klassen implementiert werden, deren Objekte in einen Suchbaum (BinarySearchTree) eingefügt werden sollen. Die Ordnungsrelation wird in diesen Klassen durch Überschreiben der drei implizit abstrakten Methoden isGreater, isEqual und isLess festgelegt.

Methode · Beschreibung

boolean isGreater(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation größer als das Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isEqual(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation gleich dem Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isLess(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation kleiner als das Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

b)

Erläutern Sie, wie die Klassen ScooterVerwaltung, Scooter, Kunde, List und BinarySearchTree untereinander und mit dem Interface ComparableContent zusammenhängen.

Begründen Sie bezogen auf den Sachkontext, warum es effizienter ist, die Scooter in einem binären Suchbaum statt in einer linearen Liste zu verwalten, während für die Kundinnen und Kunden eine Liste ausreichend ist.

[8 Punkte]

Aufgabe 2 - Algorithmen auf Feldern und linearen… · Algorithmen auf Feldern und linearen Listen

Ein neu gegründetes Startup in Köln vermietet Elektro-Roller (Scooter). Jeder Scooter besitzt einen GPS-Empfänger und sendet per Internetverbindung jede Minute seine aktuelle Position (Standort) und seinen Batterie-Zustand (Akkuladung) an den Unternehmensserver. Damit sich der Abstand zur Firmenzentrale einfach bestimmen lässt, geben die Scooter ihre Position relativ zur Firmenzentrale an (Koordinatenursprung). Auf dem Server wird die zuletzt gemeldete Position jeweils als Punkt in einem Koordinatensystem abgelegt. Abbildung 1 stellt die momentane Lage in der näheren Umgebung der Firmenzentrale dar.

Die Scooter werden im Unternehmen in einem binären Suchbaum verwaltet. Als Suchschlüssel im Baum dient die eindeutige vierstellige (Serien-)Nummer eines Scooters.

Aktuell setzt das Unternehmen die vier in Abbildung 1 gezeigten Scooter ein. Abbildung 2 zeigt den daraus entstehenden binären Suchbaum.

Die Software des Unternehmens verwaltet neben den Scooter-Daten auch die Daten der Kundinnen und Kunden, die Scooter ausleihen wollen. Vereinfachend wird jede Kundin und jeder Kunde in der Modellierung nur durch eine eindeutige E-Mail-Adresse und eine Kreditkartennummer für die Abrechnung beschrieben.

Grundlage der Software ist der in Abbildung 3 gezeigte Ausschnitt des Implementationsdiagramms.

Anhang: Dokumentationen der verwendeten Klassen

Die Klasse Scooter

Objekte dieser Klasse verwalten die Daten eines Scooters.

Methode · Beschreibung

Scooter(int pNummer) · Ein Objekt der Klasse wird initialisiert. Die eindeutige Nummer pNummer wird gespeichert.

boolean isEqual(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, gleich der Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isLess(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, kleiner als die Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isGreater(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, größer als die Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

int gibNummer() · Die Methode liefert die eindeutige Nummer des Scooters.

int gibAkkuladung() · Die Methode liefert den Batterie-Zustand des Scooters. Der Wert entspricht der Akkuladung in Prozent, d. h., der Wert liegt im Wertebereich 0 (Akku ist leer) bis 100 (Akku ist vollständig aufgeladen).

Kunde gibAusleiher() · Die Methode liefert das Objekt der Klasse Kunde, welcher den Scooter momentan ausgeliehen hat. Ist der Scooter momentan nicht verliehen, so wird null zurückgegeben.

Standort gibStandort() · Die Methode liefert ein Objekt der Klasse Standort, welches die Koordinaten relativ zur Firmenzentrale enthält. Z. B. bedeutet der Standort (-300|400), dass sich der Scooter 300 Meter in westlicher Richtung und 400 Meter in nördlicher Richtung von der Firmenzentrale befindet.

void setzeAkkuladung(int pAkkuladung) · Die Methode verändert den Wert der Akkuladung auf den Wert pAkkuladung. Ist der Wert kleiner als 0 oder größer als 100, so geschieht nichts.

void setzeAusleiher(Kunde pAusleiher) · Die Methode speichert die Daten der Person, die den Scooter momentan ausgeliehen hat. Ist der Parameter pAusleiher gleich null, so ist der Scooter wieder frei und kann von jemand anderem ausgeliehen werden.

void setzeStandort(Standort pStandort) · Die Methode setzt den Standort des Scooters auf pStandort.

Die Klasse ScooterVerwaltung

Objekte dieser Klasse verwalten Scooter sowie Kundinnen und Kunden und ermöglichen die Ausleihe von Scootern.

Methode · Beschreibung

ScooterVerwaltung() · Ein Objekt der Klasse wird initialisiert. Es verwaltet noch keine Scooter und keine Daten von Kundinnen und Kunden.

void ausleihen(String pEMailAdresse, int pScooternummer) · Die Person mit der E-Mail-Adresse pEMailAdresse leiht den Scooter mit der Nummer pScooternummer aus. Dazu speichert das zugehörige Objekt der Klasse Scooter eine Referenz auf das zugehörige Objekt der Klasse Kunde. Sollte keine Kundin und kein Kunde mit der E-Mail-Adresse pEMailAdresse bzw. kein Scooter mit der Nummer pScooternummer existieren, so geschieht nichts. Sollte der Scooter bereits ausgeliehen sein, so geschieht ebenfalls nichts.

Scooter gibScooter(int pScooternummer) · Liefert das Scooter-Objekt mit der (Serien-)Nummer pScooternummer. Falls es kein Scooter-Objekt mit der entsprechenden (Serien-)Nummer gibt, dann wird null zurückgeliefert.

List<Scooter> liefereEtwas(int pWert) · Die Methode wird in Teilaufgabe c) analysiert.

Die Klasse Kunde

Objekte dieser Klasse verwalten die Daten einer Kundin bzw. eines Kunden.

Methode · Beschreibung

Kunde(String pEMailAdresse, String pKreditkartennummer) · Ein Objekt der Klasse wird initialisiert. Die eindeutige E-Mail-Adresse pEMailAdresse der Kundin bzw. des Kunden und die zugehörige Kreditkartennummer pKreditkartennummer werden gespeichert.

String gibEMailAdresse() · Die eindeutige E-Mail-Adresse der Kundin bzw. des Kunden wird zurückgeliefert.

String gibKreditkartennummer() · Die Kreditkartennummer der Kundin bzw. des Kunden wird zurückgeliefert.

Die Klasse Standort

Objekte dieser Klasse verwalten die Koordinaten eines Standorts für Scooter. Die Koordinaten werden relativ zur Firmenzentrale gespeichert, welche sich im Koordinatenursprung befindet.

Methode · Beschreibung

Standort(int pX, int pY) · Ein Objekt der Klasse wird initialisiert. Die Koordinaten (pX|pY) werden im Objekt gespeichert.

int gibX() · Die x-Koordinate des Standorts wird zurückgeliefert. Diese entspricht der Entfernung in westlicher (bei negativem Wert) bzw. in östlicher (bei positivem Wert) Richtung in Metern von der Firmenzentrale.

int gibY() · Die y-Koordinate des Standorts wird zurückgeliefert. Diese entspricht der Entfernung in südlicher (bei negativem Wert) bzw. in nördlicher (bei positivem Wert) Richtung in Metern von der Firmenzentrale.

Die generische Klasse List<ContentType>

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden. Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Methode · Beschreibung

List() · Eine leere Liste wird erzeugt.

boolean isEmpty() · Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess() · Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next() · Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst() · Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast() · Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent() · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent) · Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent) · Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent) · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList) · Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove() · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.

Die generische Klasse BinarySearchTree<ContentType extends ComparableContent<ContentType>>

Mithilfe der generischen Klasse BinarySearchTree können beliebig viele Objekte des Typs ContentType in einem Binärbaum (binärer Suchbaum) entsprechend einer Ordnungsrelation verwaltet werden. Ein Objekt der Klasse BinarySearchTree stellt entweder einen leeren Baum dar oder verwaltet ein Inhaltsobjekt vom Typ ContentType sowie einen linken und einen rechten Teilbaum, die ebenfalls Objekte der Klasse BinarySearchTree sind. Die Klasse der Objekte, die in dem Suchbaum verwaltet werden sollen, muss das generische Interface ComparableContent implementieren. Dabei muss durch Überschreiben der drei Vergleichsmethoden isLess, isEqual, isGreater eine eindeutige Ordnungsrelation festgelegt sein.

Für je zwei Objekte c1 und c2 vom Typ ContentType gilt also insbesondere genau eine der drei Aussagen:

c1.isLess(c2) (Sprechweise: c1 ist kleiner als c2)

c1.isEqual(c2) (Sprechweise: c1 ist gleichgroß wie c2)

c1.isGreater(c2) (Sprechweise: c1 ist größer als c2)

Alle Objekte im linken Teilbaum sind kleiner als das Inhaltsobjekt des Binärbaumes. Alle Objekte im rechten Teilbaum sind größer als das Inhaltsobjekt des Binärbaumes. Diese Bedingung gilt auch in beiden Teilbäumen.

Methode · Beschreibung

BinarySearchTree() · Der Konstruktor erzeugt einen leeren Suchbaum.

boolean isEmpty() · Diese Anfrage liefert den Wahrheitswert true, wenn der Suchbaum leer ist, sonst liefert sie den Wert false.

void insert(ContentType pContent) · Falls bereits ein Objekt in dem Suchbaum vorhanden ist, das gleichgroß ist wie pContent, passiert nichts. Andernfalls wird das Objekt pContent entsprechend der Ordnungsrelation in den Baum eingeordnet. Falls der Parameter null ist, ändert sich nichts.

ContentType search(ContentType pContent) · Falls ein Objekt im binären Suchbaum enthalten ist, das gleichgroß ist wie pContent, liefert die Anfrage dieses, ansonsten wird null zurückgegeben. Falls der Parameter null ist, wird null zurückgegeben.

void remove(ContentType pContent) · Falls ein Objekt im binären Suchbaum enthalten ist, das gleichgroß ist wie pContent, wird dieses entfernt. Falls der Parameter null ist, ändert sich nichts.

ContentType getContent() · Diese Anfrage liefert das Inhaltsobjekt des Suchbaumes. Wenn der Suchbaum leer ist, wird null zurückgegeben.

BinarySearchTree<ContentType> getLeftTree() · Diese Anfrage liefert den linken Teilbaum des binären Suchbaumes. Der binäre Suchbaum ändert sich nicht. Wenn er leer ist, wird null zurückgegeben.

BinarySearchTree<ContentType> getRightTree() · Diese Anfrage liefert den rechten Teilbaum des Suchbaumes. Der Suchbaum ändert sich nicht. Wenn er leer ist, wird null zurückgegeben.

Das generische Interface ComparableContent<ContentType>

Das generische Interface ComparableContent muss von Klassen implementiert werden, deren Objekte in einen Suchbaum (BinarySearchTree) eingefügt werden sollen. Die Ordnungsrelation wird in diesen Klassen durch Überschreiben der drei implizit abstrakten Methoden isGreater, isEqual und isLess festgelegt.

Methode · Beschreibung

boolean isGreater(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation größer als das Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isEqual(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation gleich dem Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isLess(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation kleiner als das Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

d)

Nach dem Login im System möchte eine Kundin oder ein Kunde einen Scooter ausleihen. Hierfür bietet die Klasse ScooterVerwaltung die Methode ausleihen mit folgendem Methodenkopf an:

public void ausleihen(String pEMailAdresse, int pScooternummer)

Diese Methode soll den Ausleihvorgang abwickeln. Ihre Dokumentation liegt in der Anlage vor.

Implementieren Sie die Methode gemäß der vorliegenden Dokumentation.

Aufgabe 2 - Binärbäume und binäre Suchbäume · Binärbäume und binäre Suchbäume

Ein neu gegründetes Startup in Köln vermietet Elektro-Roller (Scooter). Jeder Scooter besitzt einen GPS-Empfänger und sendet per Internetverbindung jede Minute seine aktuelle Position (Standort) und seinen Batterie-Zustand (Akkuladung) an den Unternehmensserver. Damit sich der Abstand zur Firmenzentrale einfach bestimmen lässt, geben die Scooter ihre Position relativ zur Firmenzentrale an (Koordinatenursprung). Auf dem Server wird die zuletzt gemeldete Position jeweils als Punkt in einem Koordinatensystem abgelegt. Abbildung 1 stellt die momentane Lage in der näheren Umgebung der Firmenzentrale dar.

Die Scooter werden im Unternehmen in einem binären Suchbaum verwaltet. Als Suchschlüssel im Baum dient die eindeutige vierstellige (Serien-)Nummer eines Scooters.

Aktuell setzt das Unternehmen die vier in Abbildung 1 gezeigten Scooter ein. Abbildung 2 zeigt den daraus entstehenden binären Suchbaum.

Die Software des Unternehmens verwaltet neben den Scooter-Daten auch die Daten der Kundinnen und Kunden, die Scooter ausleihen wollen. Vereinfachend wird jede Kundin und jeder Kunde in der Modellierung nur durch eine eindeutige E-Mail-Adresse und eine Kreditkartennummer für die Abrechnung beschrieben.

Grundlage der Software ist der in Abbildung 3 gezeigte Ausschnitt des Implementationsdiagramms.

Anhang: Dokumentationen der verwendeten Klassen

Die Klasse Scooter

Objekte dieser Klasse verwalten die Daten eines Scooters.

Methode · Beschreibung

Scooter(int pNummer) · Ein Objekt der Klasse wird initialisiert. Die eindeutige Nummer pNummer wird gespeichert.

boolean isEqual(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, gleich der Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isLess(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, kleiner als die Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isGreater(Scooter pComparableContent) · Wenn die eindeutige Nummer des Scooter-Objekts, von dem die Methode aufgerufen wird, größer als die Nummer des Scooter-Objekts pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

int gibNummer() · Die Methode liefert die eindeutige Nummer des Scooters.

int gibAkkuladung() · Die Methode liefert den Batterie-Zustand des Scooters. Der Wert entspricht der Akkuladung in Prozent, d. h., der Wert liegt im Wertebereich 0 (Akku ist leer) bis 100 (Akku ist vollständig aufgeladen).

Kunde gibAusleiher() · Die Methode liefert das Objekt der Klasse Kunde, welcher den Scooter momentan ausgeliehen hat. Ist der Scooter momentan nicht verliehen, so wird null zurückgegeben.

Standort gibStandort() · Die Methode liefert ein Objekt der Klasse Standort, welches die Koordinaten relativ zur Firmenzentrale enthält. Z. B. bedeutet der Standort (-300|400), dass sich der Scooter 300 Meter in westlicher Richtung und 400 Meter in nördlicher Richtung von der Firmenzentrale befindet.

void setzeAkkuladung(int pAkkuladung) · Die Methode verändert den Wert der Akkuladung auf den Wert pAkkuladung. Ist der Wert kleiner als 0 oder größer als 100, so geschieht nichts.

void setzeAusleiher(Kunde pAusleiher) · Die Methode speichert die Daten der Person, die den Scooter momentan ausgeliehen hat. Ist der Parameter pAusleiher gleich null, so ist der Scooter wieder frei und kann von jemand anderem ausgeliehen werden.

void setzeStandort(Standort pStandort) · Die Methode setzt den Standort des Scooters auf pStandort.

Die Klasse ScooterVerwaltung

Objekte dieser Klasse verwalten Scooter sowie Kundinnen und Kunden und ermöglichen die Ausleihe von Scootern.

Methode · Beschreibung

ScooterVerwaltung() · Ein Objekt der Klasse wird initialisiert. Es verwaltet noch keine Scooter und keine Daten von Kundinnen und Kunden.

void ausleihen(String pEMailAdresse, int pScooternummer) · Die Person mit der E-Mail-Adresse pEMailAdresse leiht den Scooter mit der Nummer pScooternummer aus. Dazu speichert das zugehörige Objekt der Klasse Scooter eine Referenz auf das zugehörige Objekt der Klasse Kunde. Sollte keine Kundin und kein Kunde mit der E-Mail-Adresse pEMailAdresse bzw. kein Scooter mit der Nummer pScooternummer existieren, so geschieht nichts. Sollte der Scooter bereits ausgeliehen sein, so geschieht ebenfalls nichts.

Scooter gibScooter(int pScooternummer) · Liefert das Scooter-Objekt mit der (Serien-)Nummer pScooternummer. Falls es kein Scooter-Objekt mit der entsprechenden (Serien-)Nummer gibt, dann wird null zurückgeliefert.

List<Scooter> liefereEtwas(int pWert) · Die Methode wird in Teilaufgabe c) analysiert.

Die Klasse Kunde

Objekte dieser Klasse verwalten die Daten einer Kundin bzw. eines Kunden.

Methode · Beschreibung

Kunde(String pEMailAdresse, String pKreditkartennummer) · Ein Objekt der Klasse wird initialisiert. Die eindeutige E-Mail-Adresse pEMailAdresse der Kundin bzw. des Kunden und die zugehörige Kreditkartennummer pKreditkartennummer werden gespeichert.

String gibEMailAdresse() · Die eindeutige E-Mail-Adresse der Kundin bzw. des Kunden wird zurückgeliefert.

String gibKreditkartennummer() · Die Kreditkartennummer der Kundin bzw. des Kunden wird zurückgeliefert.

Die Klasse Standort

Objekte dieser Klasse verwalten die Koordinaten eines Standorts für Scooter. Die Koordinaten werden relativ zur Firmenzentrale gespeichert, welche sich im Koordinatenursprung befindet.

Methode · Beschreibung

Standort(int pX, int pY) · Ein Objekt der Klasse wird initialisiert. Die Koordinaten (pX|pY) werden im Objekt gespeichert.

int gibX() · Die x-Koordinate des Standorts wird zurückgeliefert. Diese entspricht der Entfernung in westlicher (bei negativem Wert) bzw. in östlicher (bei positivem Wert) Richtung in Metern von der Firmenzentrale.

int gibY() · Die y-Koordinate des Standorts wird zurückgeliefert. Diese entspricht der Entfernung in südlicher (bei negativem Wert) bzw. in nördlicher (bei positivem Wert) Richtung in Metern von der Firmenzentrale.

Die generische Klasse List<ContentType>

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden. Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Methode · Beschreibung

List() · Eine leere Liste wird erzeugt.

boolean isEmpty() · Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess() · Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next() · Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst() · Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast() · Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent() · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent) · Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent) · Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent) · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList) · Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove() · Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.

Die generische Klasse BinarySearchTree<ContentType extends ComparableContent<ContentType>>

Mithilfe der generischen Klasse BinarySearchTree können beliebig viele Objekte des Typs ContentType in einem Binärbaum (binärer Suchbaum) entsprechend einer Ordnungsrelation verwaltet werden. Ein Objekt der Klasse BinarySearchTree stellt entweder einen leeren Baum dar oder verwaltet ein Inhaltsobjekt vom Typ ContentType sowie einen linken und einen rechten Teilbaum, die ebenfalls Objekte der Klasse BinarySearchTree sind. Die Klasse der Objekte, die in dem Suchbaum verwaltet werden sollen, muss das generische Interface ComparableContent implementieren. Dabei muss durch Überschreiben der drei Vergleichsmethoden isLess, isEqual, isGreater eine eindeutige Ordnungsrelation festgelegt sein.

Für je zwei Objekte c1 und c2 vom Typ ContentType gilt also insbesondere genau eine der drei Aussagen:

c1.isLess(c2) (Sprechweise: c1 ist kleiner als c2)

c1.isEqual(c2) (Sprechweise: c1 ist gleichgroß wie c2)

c1.isGreater(c2) (Sprechweise: c1 ist größer als c2)

Alle Objekte im linken Teilbaum sind kleiner als das Inhaltsobjekt des Binärbaumes. Alle Objekte im rechten Teilbaum sind größer als das Inhaltsobjekt des Binärbaumes. Diese Bedingung gilt auch in beiden Teilbäumen.

Methode · Beschreibung

BinarySearchTree() · Der Konstruktor erzeugt einen leeren Suchbaum.

boolean isEmpty() · Diese Anfrage liefert den Wahrheitswert true, wenn der Suchbaum leer ist, sonst liefert sie den Wert false.

void insert(ContentType pContent) · Falls bereits ein Objekt in dem Suchbaum vorhanden ist, das gleichgroß ist wie pContent, passiert nichts. Andernfalls wird das Objekt pContent entsprechend der Ordnungsrelation in den Baum eingeordnet. Falls der Parameter null ist, ändert sich nichts.

ContentType search(ContentType pContent) · Falls ein Objekt im binären Suchbaum enthalten ist, das gleichgroß ist wie pContent, liefert die Anfrage dieses, ansonsten wird null zurückgegeben. Falls der Parameter null ist, wird null zurückgegeben.

void remove(ContentType pContent) · Falls ein Objekt im binären Suchbaum enthalten ist, das gleichgroß ist wie pContent, wird dieses entfernt. Falls der Parameter null ist, ändert sich nichts.

ContentType getContent() · Diese Anfrage liefert das Inhaltsobjekt des Suchbaumes. Wenn der Suchbaum leer ist, wird null zurückgegeben.

BinarySearchTree<ContentType> getLeftTree() · Diese Anfrage liefert den linken Teilbaum des binären Suchbaumes. Der binäre Suchbaum ändert sich nicht. Wenn er leer ist, wird null zurückgegeben.

BinarySearchTree<ContentType> getRightTree() · Diese Anfrage liefert den rechten Teilbaum des Suchbaumes. Der Suchbaum ändert sich nicht. Wenn er leer ist, wird null zurückgegeben.

Das generische Interface ComparableContent<ContentType>

Das generische Interface ComparableContent muss von Klassen implementiert werden, deren Objekte in einen Suchbaum (BinarySearchTree) eingefügt werden sollen. Die Ordnungsrelation wird in diesen Klassen durch Überschreiben der drei implizit abstrakten Methoden isGreater, isEqual und isLess festgelegt.

Methode · Beschreibung

boolean isGreater(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation größer als das Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isEqual(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation gleich dem Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

boolean isLess(ContentType pComparableContent) · Wenn festgestellt wird, dass das Objekt, von dem die Methode aufgerufen wird, bzgl. der gewünschten Ordnungsrelation kleiner als das Objekt pComparableContent ist, wird true geliefert. Sonst wird false geliefert.

Teilaufgabe a)

Das Unternehmen verfügt über weitere Scooter, die in den bestehenden Datenbestand aufgenommen werden sollen. Zuerst werden vier Scooter mit den Nummern 4999, 4400, 1000 und 8500 exakt in dieser Reihenfolge in den Suchbaum aus Abbildung 2 eingefügt.

Stellen Sie den Suchbaum, der sich nach dem Einfügen ergibt, grafisch dar.

Stellen Sie den Suchbaum grafisch dar, der sich aus dem Suchbaum mit den acht Suchschlüsseln ergibt, wenn der Scooter mit der Nummer 4671 gestohlen wurde und daher aus dem System entfernt werden muss.

Teilaufgabe c)

Die Klasse ScooterVerwaltung enthält die folgenden Methoden:

1 public List<Scooter> liefereEtwas(int pWert) {

2 return liefereEtwas(pWert, alleScooter);

3 }

4

5 private List<Scooter> liefereEtwas(

6 int pWert, BinarySearchTree<Scooter> pBaum) {

7 List<Scooter> ergebnis = new List<Scooter>();

8 if (!pBaum.isEmpty()) {

9 ergebnis.concat(

10 liefereEtwas(pWert, pBaum.getLeftTree()));

11 Scooter s = pBaum.getContent();

12 if (pWert >= s.gibAkkuladung()) {

13 ergebnis.append(s);

14 }

15 ergebnis.concat(

16 liefereEtwas(pWert, pBaum.getRightTree()));

17 }

18 return ergebnis;

19 } Angenommen, der binäre Suchbaum alleScooter enthält den Suchbaum aus Abbildung 2 mit den Suchschlüsseln der Scooter aus Abbildung 1. Die öffentliche Methode liefereEtwas wird mit dem Parameter pWert = 80 aufgerufen.

Analysieren Sie den Quelltext der beiden Methoden, indem Sie diese auf die Beispieldaten anwenden und die dabei entstehende Rückgabe-Liste ermitteln.

Erläutern Sie, wie die private Methode arbeitet.

Erläutern Sie im Sachkontext, welche Information die öffentliche Methode zurückgibt.

Teilaufgabe e)

Jeden Abend soll kontrolliert werden, ob sämtliche Scooter vorschriftsmäßig abgestellt sind. Dafür setzt das Unternehmen eine Drohne ein, die abends alle Scooter anfliegt und von jedem ein Foto an die Firmenzentrale sendet. Sind alle Scooter fotografiert, kehrt die Drohne zur Firmenzentrale zurück.

Ein Praktikant empfiehlt, die Scooter zuerst aufsteigend nach ihrer Entfernung von der Firmenzentrale zu sortieren und in dieser Ordnung in einer Liste abzulegen.

Anhand dieser Liste könnte die Drohne die Scooter nacheinander anfliegen und fotografieren.

Wenden Sie die Strategie des Praktikanten auf die Beispieldaten der Scooter aus Abbildung 1 an, indem Sie ermitteln, in welcher Reihenfolge die Scooter angeflogen werden.

Entwickeln Sie eine Strategie für einen Algorithmus, der eine derart sortierte Liste aller im Baum alleScooter gespeicherten Scooter-Objekte erzeugt.

Begründen Sie anhand eines selbst gewählten Beispiels im Sachkontext, weshalb die Strategie des Praktikanten nicht stets eine optimale Flugroute liefert.

Aufgabe 3 - Datenbankmodellierung und Normalisier… · Datenbankmodellierung und Normalisierung

Aufgabenstellung

Ein Unternehmen plant die Entwicklung einer App, mit der sich mehrere Einkaufslisten anlegen und verwalten lassen.

Wer die App nutzen möchte, muss sich mit dem eigenen Namen, einem eindeutigen Benutzernamen und einem Passwort registrieren. Dabei ist die Zustimmung erforderlich, dass die Angaben zur Bereitstellung aller Dienste der App gespeichert und verarbeitet werden dürfen.

Damit das Anlegen einer Einkaufsliste einfacher wird, sind im System schon zahlreiche Produkte hinterlegt, die ausgewählt werden können. Selbstverständlich dürfen Nutzerinnen und Nutzer auch eigene neue Produkte ergänzen.

Das Unternehmen hält seine Daten in einer relationalen Datenbank. Ein Teil der Modellierung dieser Datenbank wird nachfolgend gezeigt.

Die Modellierung führt zu dem folgenden Datenbankschema. Im Anhang stehen Beispieldatensätze zu diesem Schema.

Anlage: Beispieldaten

Einkaufsliste

ID · Titel · Benutzername

14 · Salatliste · Linus

15 · Biomarkt · FabBen

16 · Hamstern · FabBen

17 · Einkaufen · Linus

18 · Geburtstagsfeier · FabBen

19 · Biomarkt · JaStIn

Produkt

Bezeichnung · Kategorie

Schafskäse · Kühlprodukte

Gouda · Kühlprodukte

Hefe · Kühlprodukte

Brot · Backwaren

Baguette · Backwaren

Paprika · Obst/Gemüse

Gurke · Obst/Gemüse

Salat · Obst/Gemüse

Salamipizza · Tiefkühlprodukte

Erbsen · Tiefkühlprodukte

Schokolade · Süßspeisen

Bonbons · Süßspeisen

Limonade · Getränke

Klopapier · Hygieneartikel

Biomango · Obst/Gemüse

Benutzer

Benutzername · Vorname · Nachname · Passwort 1

FabBen · Ben · Lovelace · ab4bd73e2123ddef3

JaStIn · Jana · Strehl · 3e2123ddef3ab4bd7

Edelweiss · Julian · Beton · ab4bd7ab4bd7eefde

Pudelski · Laura · Pudelski · bd7ab4bd7eef00e0e

Linus · Knut · Bremhorst · ef0023ddef3ab47ea

1 Die Passwörter werden nicht im Klartext, sondern verschlüsselt in der Datenbank gespeichert.

stehtAuf

ProduktBezeichnung · EinkaufslisteID · Menge

Schafskäse · 14 · 2

Schokolade · 15 · 3

Salat · 14 · 1

Paprika · 14 · 1

Limonade · 18 · 24

Bonbons · 18 · 3

Brot · 16 · 5

Gouda · 15 · 1

Brot · 18 · 3

Gurke · 17 · 2

Paprika · 17 · 1

Baguette · 18 · 6

Salamipizza · 17 · 3

Schafskäse · 15 · 2

Schokolade · 18 · 1

Erbsen · 18 · 1

Schokolade · 17 · 2

Hefe · 17 · 1

Hefe · 16 · 12

Klopapier · 16 · 25

Anhang: Dokumentation der Klassen

Die Klasse EinkaufslistenApp

Ein Objekt der Klasse EinkaufslistenApp verwaltet eine aus der passenden Datenbank geladene Einkaufsliste.

Ausschnitt aus der Dokumentation der Klasse EinkaufslistenApp

EinkaufslistenApp(String pBenutzername, String pPasswort) Ein neues Objekt der Klasse wird mit den Parametern pBenutzername und pPasswort initialisiert.

int[] ladeListenIDs() Die Methode lädt die IDs der Einkaufslisten aus der Datenbank, die der angemeldeten Person zugeordnet sind, und gibt sie zurück.

void ladeListe(int pID) Die Methode lädt die Einträge der mit der ID identifizierten Einkaufsliste aus der Datenbank und speichert sie. Existiert die ID nicht oder ist keine Benutzerin bzw. kein Benutzer angemeldet, so wird keine Einkaufsliste gespeichert.

int gibAktuelleID() Die Methode liefert die ID zu der aktuell geladenen Einkaufsliste. Ist keine Einkaufsliste geladen, wird -1 zurückgegeben.

List<Eintrag> gibAktuelleEintraege() Die Methode liefert die Einträge der aktuellen Einkaufsliste in einem Objekt der Klasse Liste<Eintrag>. Ist keine aktuelle Einkaufsliste geladen, so wird null zurückgegeben.

Die Klasse Eintrag

Ein Objekt der Klasse Eintrag verwaltet ein aus der passenden Datenbank geladenes Produkt sowie die für die zugehörige Einkaufsliste gespeicherte Menge.

Ausschnitt aus der Dokumentation der Klasse Eintrag

Eintrag(Produkt pProdukt, int pMenge) Ein neues Objekt der Klasse wird mit den Parametern pProdukt und pMenge initialisiert.

void setzeErledigt(boolean pErledigt) Die Methode speichert, ob der Eintrag erledigt ist.

boolean istErledigt() Die Methode liefert, ob der Eintrag erledigt ist.

int gibMenge() Die Methode liefert die gespeicherte Menge des Eintrags.

Produkt gibProdukt() Die Methode liefert das Produkt zu dem Eintrag.

Die Klasse Produkt

Ein Objekt der Klasse Produkt repräsentiert ein aus der passenden Datenbank geladenes Produkt.

Ausschnitt aus der Dokumentation der Klasse Produkt

Produkt(String pBezeichnung, String pKategorie) Ein neues Objekt der Klasse wird mit den Parametern pBezeichnung und pKategorie initialisiert.

String gibBezeichnung() Die Methode liefert die gespeicherte Bezeichnung des Produkts.

String gibKategorie() Die Methode liefert die Kategorie des Produkts.

Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden. Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List() Eine leere Liste wird erzeugt.

boolean isEmpty() Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess() Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next() Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst() Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast() Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent() Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent) Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent) Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent) Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList) Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove() Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.

Die Klasse DatabaseConnector

Ein Objekt der Klasse DatabaseConnector ermöglicht die Abfrage und Manipulation einer relationalen Datenbank. Beim Erzeugen des Objekts wird eine Datenbankverbindung aufgebaut, sodass anschließend SQL-Anweisungen an diese Datenbank gerichtet werden können.

Dokumentation der Klasse DatabaseConnector

DatabaseConnector(String pIP, int pPort, String pDatabase, String pUsername, String pPassword) Ein Objekt vom Typ DatabaseConnector wird erstellt, und eine Verbindung zur Datenbank wird aufgebaut. Mit den Parametern pIP und pPort werden die IP-Adresse und die Port-Nummer übergeben, unter denen die Datenbank mit Namen pDatabase zu erreichen ist. Mit den Parametern pUsername und pPassword werden Benutzername und Passwort für die Datenbank übergeben.

void executeStatement(String pSQLStatement) Der Auftrag schickt den im Parameter pSQLStatement enthaltenen SQL-Befehl an die Datenbank ab. Handelt es sich bei pSQLStatement um einen SQL-Befehl, der eine Ergebnismenge liefert, so kann dieses Ergebnis anschließend mit der Methode getCurrentQueryResult abgerufen werden.

QueryResult getCurrentQueryResult() Die Anfrage liefert das Ergebnis des letzten mit der Methode executeStatement an die Datenbank geschickten SQL-Befehls als Objekt vom Typ QueryResult zurück. Wurde bisher kein SQL-Befehl abgeschickt oder ergab der letzte Aufruf von executeStatement keine Ergebnismenge (z. B. bei einem INSERT-Befehl oder einem Syntaxfehler), so wird null geliefert.

String getErrorMessage() Die Anfrage liefert null oder eine Fehlermeldung, die sich jeweils auf die letzte zuvor ausgeführte Datenbankoperation bezieht.

void close() Die Datenbankverbindung wird geschlossen.

Die Klasse QueryResult

Ein Objekt der Klasse QueryResult stellt die Ergebnistabelle einer Datenbankanfrage mit Hilfe der Klasse DatabaseConnector dar. Objekte dieser Klasse werden nur von der Klasse DatabaseConnector erstellt. Die Klasse verfügt über keinen öffentlichen Konstruktor.

Dokumentation der Klasse QueryResult

String[][] getData() Die Anfrage liefert die Einträge der Ergebnistabelle als zweidimensionales Feld vom Typ String. Der erste Index des Feldes stellt die Zeile und der zweite die Spalte dar (d. h. String[zeile][spalte]).

String[] getColumnNames() Die Anfrage liefert die Bezeichner der Spalten der Ergebnistabelle als Feld vom Typ String zurück.

String[] getColumnTypes() Die Anfrage liefert die Typenbezeichnung der Spalten der Ergebnistabelle als Feld vom Typ String zurück. Die Bezeichnungen entsprechen den Angaben in der Datenbank.

int getRowCount() Die Anfrage liefert die Anzahl der Zeilen der Ergebnistabelle als int.

int getColumnCount() Die Anfrage liefert die Anzahl der Spalten der Ergebnistabelle als int.

a)

Erläutern Sie, was der Beziehungstyp stehtAuf im gegebenen Sachzusammenhang bedeutet.

Beschreiben Sie, wie der Beziehungstyp stehtAuf im Datenbankschema umgesetzt wird.

Begründen Sie in diesem Kontext, weshalb das Attribut Menge dem Relationenschema stehtAuf und nicht dem Relationenschema Produkt zugeordnet ist.

[8 Punkte]

d)

Erläutern Sie die Assoziationen, die Abbildung 4 zeigt, im Sachkontext.

Vergleichen Sie das Implementationsdiagramm in Abbildung 4 mit dem Entity-Relationship-Diagramm in Abbildung 2 und erläutern Sie, welche Gemeinsamkeiten und Unterschiede sich bei den in der App bzw. in der Datenbank modellierten Daten zeigen.

Hinweis: Ziehen Sie hierfür auch die Dokumentationen im Anhang heran.

[13 Punkte]

Aufgabe 3 - SQL-Abfragen · SQL-Abfragen

Aufgabenstellung

Ein Unternehmen plant die Entwicklung einer App, mit der sich mehrere Einkaufslisten anlegen und verwalten lassen.

Wer die App nutzen möchte, muss sich mit dem eigenen Namen, einem eindeutigen Benutzernamen und einem Passwort registrieren. Dabei ist die Zustimmung erforderlich, dass die Angaben zur Bereitstellung aller Dienste der App gespeichert und verarbeitet werden dürfen.

Damit das Anlegen einer Einkaufsliste einfacher wird, sind im System schon zahlreiche Produkte hinterlegt, die ausgewählt werden können. Selbstverständlich dürfen Nutzerinnen und Nutzer auch eigene neue Produkte ergänzen.

Das Unternehmen hält seine Daten in einer relationalen Datenbank. Ein Teil der Modellierung dieser Datenbank wird nachfolgend gezeigt.

Die Modellierung führt zu dem folgenden Datenbankschema. Im Anhang stehen Beispieldatensätze zu diesem Schema.

Anlage: Beispieldaten

Einkaufsliste

ID · Titel · Benutzername

14 · Salatliste · Linus

15 · Biomarkt · FabBen

16 · Hamstern · FabBen

17 · Einkaufen · Linus

18 · Geburtstagsfeier · FabBen

19 · Biomarkt · JaStIn

Produkt

Bezeichnung · Kategorie

Schafskäse · Kühlprodukte

Gouda · Kühlprodukte

Hefe · Kühlprodukte

Brot · Backwaren

Baguette · Backwaren

Paprika · Obst/Gemüse

Gurke · Obst/Gemüse

Salat · Obst/Gemüse

Salamipizza · Tiefkühlprodukte

Erbsen · Tiefkühlprodukte

Schokolade · Süßspeisen

Bonbons · Süßspeisen

Limonade · Getränke

Klopapier · Hygieneartikel

Biomango · Obst/Gemüse

Benutzer

Benutzername · Vorname · Nachname · Passwort 1

FabBen · Ben · Lovelace · ab4bd73e2123ddef3

JaStIn · Jana · Strehl · 3e2123ddef3ab4bd7

Edelweiss · Julian · Beton · ab4bd7ab4bd7eefde

Pudelski · Laura · Pudelski · bd7ab4bd7eef00e0e

Linus · Knut · Bremhorst · ef0023ddef3ab47ea

1 Die Passwörter werden nicht im Klartext, sondern verschlüsselt in der Datenbank gespeichert.

stehtAuf

ProduktBezeichnung · EinkaufslisteID · Menge

Schafskäse · 14 · 2

Schokolade · 15 · 3

Salat · 14 · 1

Paprika · 14 · 1

Limonade · 18 · 24

Bonbons · 18 · 3

Brot · 16 · 5

Gouda · 15 · 1

Brot · 18 · 3

Gurke · 17 · 2

Paprika · 17 · 1

Baguette · 18 · 6

Salamipizza · 17 · 3

Schafskäse · 15 · 2

Schokolade · 18 · 1

Erbsen · 18 · 1

Schokolade · 17 · 2

Hefe · 17 · 1

Hefe · 16 · 12

Klopapier · 16 · 25

Anhang: Dokumentation der Klassen

Die Klasse EinkaufslistenApp

Ein Objekt der Klasse EinkaufslistenApp verwaltet eine aus der passenden Datenbank geladene Einkaufsliste.

Ausschnitt aus der Dokumentation der Klasse EinkaufslistenApp

EinkaufslistenApp(String pBenutzername, String pPasswort) Ein neues Objekt der Klasse wird mit den Parametern pBenutzername und pPasswort initialisiert.

int[] ladeListenIDs() Die Methode lädt die IDs der Einkaufslisten aus der Datenbank, die der angemeldeten Person zugeordnet sind, und gibt sie zurück.

void ladeListe(int pID) Die Methode lädt die Einträge der mit der ID identifizierten Einkaufsliste aus der Datenbank und speichert sie. Existiert die ID nicht oder ist keine Benutzerin bzw. kein Benutzer angemeldet, so wird keine Einkaufsliste gespeichert.

int gibAktuelleID() Die Methode liefert die ID zu der aktuell geladenen Einkaufsliste. Ist keine Einkaufsliste geladen, wird -1 zurückgegeben.

List<Eintrag> gibAktuelleEintraege() Die Methode liefert die Einträge der aktuellen Einkaufsliste in einem Objekt der Klasse Liste<Eintrag>. Ist keine aktuelle Einkaufsliste geladen, so wird null zurückgegeben.

Die Klasse Eintrag

Ein Objekt der Klasse Eintrag verwaltet ein aus der passenden Datenbank geladenes Produkt sowie die für die zugehörige Einkaufsliste gespeicherte Menge.

Ausschnitt aus der Dokumentation der Klasse Eintrag

Eintrag(Produkt pProdukt, int pMenge) Ein neues Objekt der Klasse wird mit den Parametern pProdukt und pMenge initialisiert.

void setzeErledigt(boolean pErledigt) Die Methode speichert, ob der Eintrag erledigt ist.

boolean istErledigt() Die Methode liefert, ob der Eintrag erledigt ist.

int gibMenge() Die Methode liefert die gespeicherte Menge des Eintrags.

Produkt gibProdukt() Die Methode liefert das Produkt zu dem Eintrag.

Die Klasse Produkt

Ein Objekt der Klasse Produkt repräsentiert ein aus der passenden Datenbank geladenes Produkt.

Ausschnitt aus der Dokumentation der Klasse Produkt

Produkt(String pBezeichnung, String pKategorie) Ein neues Objekt der Klasse wird mit den Parametern pBezeichnung und pKategorie initialisiert.

String gibBezeichnung() Die Methode liefert die gespeicherte Bezeichnung des Produkts.

String gibKategorie() Die Methode liefert die Kategorie des Produkts.

Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden. Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List() Eine leere Liste wird erzeugt.

boolean isEmpty() Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess() Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next() Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst() Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast() Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent() Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent) Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent) Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent) Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList) Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove() Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.

Die Klasse DatabaseConnector

Ein Objekt der Klasse DatabaseConnector ermöglicht die Abfrage und Manipulation einer relationalen Datenbank. Beim Erzeugen des Objekts wird eine Datenbankverbindung aufgebaut, sodass anschließend SQL-Anweisungen an diese Datenbank gerichtet werden können.

Dokumentation der Klasse DatabaseConnector

DatabaseConnector(String pIP, int pPort, String pDatabase, String pUsername, String pPassword) Ein Objekt vom Typ DatabaseConnector wird erstellt, und eine Verbindung zur Datenbank wird aufgebaut. Mit den Parametern pIP und pPort werden die IP-Adresse und die Port-Nummer übergeben, unter denen die Datenbank mit Namen pDatabase zu erreichen ist. Mit den Parametern pUsername und pPassword werden Benutzername und Passwort für die Datenbank übergeben.

void executeStatement(String pSQLStatement) Der Auftrag schickt den im Parameter pSQLStatement enthaltenen SQL-Befehl an die Datenbank ab. Handelt es sich bei pSQLStatement um einen SQL-Befehl, der eine Ergebnismenge liefert, so kann dieses Ergebnis anschließend mit der Methode getCurrentQueryResult abgerufen werden.

QueryResult getCurrentQueryResult() Die Anfrage liefert das Ergebnis des letzten mit der Methode executeStatement an die Datenbank geschickten SQL-Befehls als Objekt vom Typ QueryResult zurück. Wurde bisher kein SQL-Befehl abgeschickt oder ergab der letzte Aufruf von executeStatement keine Ergebnismenge (z. B. bei einem INSERT-Befehl oder einem Syntaxfehler), so wird null geliefert.

String getErrorMessage() Die Anfrage liefert null oder eine Fehlermeldung, die sich jeweils auf die letzte zuvor ausgeführte Datenbankoperation bezieht.

void close() Die Datenbankverbindung wird geschlossen.

Die Klasse QueryResult

Ein Objekt der Klasse QueryResult stellt die Ergebnistabelle einer Datenbankanfrage mit Hilfe der Klasse DatabaseConnector dar. Objekte dieser Klasse werden nur von der Klasse DatabaseConnector erstellt. Die Klasse verfügt über keinen öffentlichen Konstruktor.

Dokumentation der Klasse QueryResult

String[][] getData() Die Anfrage liefert die Einträge der Ergebnistabelle als zweidimensionales Feld vom Typ String. Der erste Index des Feldes stellt die Zeile und der zweite die Spalte dar (d. h. String[zeile][spalte]).

String[] getColumnNames() Die Anfrage liefert die Bezeichner der Spalten der Ergebnistabelle als Feld vom Typ String zurück.

String[] getColumnTypes() Die Anfrage liefert die Typenbezeichnung der Spalten der Ergebnistabelle als Feld vom Typ String zurück. Die Bezeichnungen entsprechen den Angaben in der Datenbank.

int getRowCount() Die Anfrage liefert die Anzahl der Zeilen der Ergebnistabelle als int.

int getColumnCount() Die Anfrage liefert die Anzahl der Spalten der Ergebnistabelle als int.

Teilaufgabe b [11 Punkte]

Aus der Datenbank, die nach dem Schema in Abbildung 3 aufgebaut ist, sollen die nachfolgend beschriebenen Informationen abgefragt werden.

Entwerfen Sie zu jeder der oben genannten Anfragen eine passende SQL-Anweisung.

i.

Gesucht sind die Titel sämtlicher Einkaufslisten, die der Person mit dem Benutzernamen FabBen gehören.

ii.

Gesucht sind Bezeichnung und Kategorie der Produkte, die auf der Einkaufsliste mit der ID 18 aufgeführt sind. Die Ausgabe soll zuerst nach der Kategorie absteigend und anschließend nach der Bezeichnung aufsteigend sortiert sein.

iii.

Es soll bestimmt werden, aus welchen Kategorien der Benutzer mit dem Benutzernamen Linus Produkte auf seinen Listen führt. Zusätzlich soll zu jeder dieser Kategorien die Summe der Mengenangaben berechnet werden.

Teilaufgabe c [12 Punkte]

Betrachtet wird die folgende SQL-Anweisung:

1 SELECT Einkaufsliste.Benutzername

2 FROM Einkaufsliste

3 WHERE Einkaufsliste.Benutzername NOT IN (

4 SELECT Einkaufsliste.Benutzername

5 FROM Einkaufsliste

6 WHERE Einkaufsliste.ID IN (

7 SELECT stehtAuf.EinkaufslisteID

8 FROM stehtAuf

9 WHERE stehtAuf.ProduktBezeichnung = 'Schokolade'

10)

11)

1.

Analysieren Sie die Unteranfragen in Zeile 7 bis 9 sowie in Zeile 4 bis 10, indem Sie diese auf die Beispieldaten (siehe Anlage) anwenden und das jeweilige Ergebnis angeben.

2.

Ermitteln Sie mithilfe der Beispieldaten, welches Ergebnis die vollständige Anfrage liefert.

3.

Erläutern Sie, welche Informationen die gesamte Anfrage im Sachkontext liefert.

4.

Beurteilen Sie das Ergebnis der SQL-Anfrage im Sachkontext hinsichtlich des Benutzers mit dem Benutzernamen Edelweiss.

Aufgabe 3 - Datenschutz und Datensicherheit · Datenschutz und Datensicherheit

Aufgabenstellung

Ein Unternehmen plant die Entwicklung einer App, mit der sich mehrere Einkaufslisten anlegen und verwalten lassen.

Wer die App nutzen möchte, muss sich mit dem eigenen Namen, einem eindeutigen Benutzernamen und einem Passwort registrieren. Dabei ist die Zustimmung erforderlich, dass die Angaben zur Bereitstellung aller Dienste der App gespeichert und verarbeitet werden dürfen.

Damit das Anlegen einer Einkaufsliste einfacher wird, sind im System schon zahlreiche Produkte hinterlegt, die ausgewählt werden können. Selbstverständlich dürfen Nutzerinnen und Nutzer auch eigene neue Produkte ergänzen.

Das Unternehmen hält seine Daten in einer relationalen Datenbank. Ein Teil der Modellierung dieser Datenbank wird nachfolgend gezeigt.

Die Modellierung führt zu dem folgenden Datenbankschema. Im Anhang stehen Beispieldatensätze zu diesem Schema.

Anlage: Beispieldaten

Einkaufsliste

ID · Titel · Benutzername

14 · Salatliste · Linus

15 · Biomarkt · FabBen

16 · Hamstern · FabBen

17 · Einkaufen · Linus

18 · Geburtstagsfeier · FabBen

19 · Biomarkt · JaStIn

Produkt

Bezeichnung · Kategorie

Schafskäse · Kühlprodukte

Gouda · Kühlprodukte

Hefe · Kühlprodukte

Brot · Backwaren

Baguette · Backwaren

Paprika · Obst/Gemüse

Gurke · Obst/Gemüse

Salat · Obst/Gemüse

Salamipizza · Tiefkühlprodukte

Erbsen · Tiefkühlprodukte

Schokolade · Süßspeisen

Bonbons · Süßspeisen

Limonade · Getränke

Klopapier · Hygieneartikel

Biomango · Obst/Gemüse

Benutzer

Benutzername · Vorname · Nachname · Passwort 1

FabBen · Ben · Lovelace · ab4bd73e2123ddef3

JaStIn · Jana · Strehl · 3e2123ddef3ab4bd7

Edelweiss · Julian · Beton · ab4bd7ab4bd7eefde

Pudelski · Laura · Pudelski · bd7ab4bd7eef00e0e

Linus · Knut · Bremhorst · ef0023ddef3ab47ea

1 Die Passwörter werden nicht im Klartext, sondern verschlüsselt in der Datenbank gespeichert.

stehtAuf

ProduktBezeichnung · EinkaufslisteID · Menge

Schafskäse · 14 · 2

Schokolade · 15 · 3

Salat · 14 · 1

Paprika · 14 · 1

Limonade · 18 · 24

Bonbons · 18 · 3

Brot · 16 · 5

Gouda · 15 · 1

Brot · 18 · 3

Gurke · 17 · 2

Paprika · 17 · 1

Baguette · 18 · 6

Salamipizza · 17 · 3

Schafskäse · 15 · 2

Schokolade · 18 · 1

Erbsen · 18 · 1

Schokolade · 17 · 2

Hefe · 17 · 1

Hefe · 16 · 12

Klopapier · 16 · 25

Anhang: Dokumentation der Klassen

Die Klasse EinkaufslistenApp

Ein Objekt der Klasse EinkaufslistenApp verwaltet eine aus der passenden Datenbank geladene Einkaufsliste.

Ausschnitt aus der Dokumentation der Klasse EinkaufslistenApp

EinkaufslistenApp(String pBenutzername, String pPasswort) Ein neues Objekt der Klasse wird mit den Parametern pBenutzername und pPasswort initialisiert.

int[] ladeListenIDs() Die Methode lädt die IDs der Einkaufslisten aus der Datenbank, die der angemeldeten Person zugeordnet sind, und gibt sie zurück.

void ladeListe(int pID) Die Methode lädt die Einträge der mit der ID identifizierten Einkaufsliste aus der Datenbank und speichert sie. Existiert die ID nicht oder ist keine Benutzerin bzw. kein Benutzer angemeldet, so wird keine Einkaufsliste gespeichert.

int gibAktuelleID() Die Methode liefert die ID zu der aktuell geladenen Einkaufsliste. Ist keine Einkaufsliste geladen, wird -1 zurückgegeben.

List<Eintrag> gibAktuelleEintraege() Die Methode liefert die Einträge der aktuellen Einkaufsliste in einem Objekt der Klasse Liste<Eintrag>. Ist keine aktuelle Einkaufsliste geladen, so wird null zurückgegeben.

Die Klasse Eintrag

Ein Objekt der Klasse Eintrag verwaltet ein aus der passenden Datenbank geladenes Produkt sowie die für die zugehörige Einkaufsliste gespeicherte Menge.

Ausschnitt aus der Dokumentation der Klasse Eintrag

Eintrag(Produkt pProdukt, int pMenge) Ein neues Objekt der Klasse wird mit den Parametern pProdukt und pMenge initialisiert.

void setzeErledigt(boolean pErledigt) Die Methode speichert, ob der Eintrag erledigt ist.

boolean istErledigt() Die Methode liefert, ob der Eintrag erledigt ist.

int gibMenge() Die Methode liefert die gespeicherte Menge des Eintrags.

Produkt gibProdukt() Die Methode liefert das Produkt zu dem Eintrag.

Die Klasse Produkt

Ein Objekt der Klasse Produkt repräsentiert ein aus der passenden Datenbank geladenes Produkt.

Ausschnitt aus der Dokumentation der Klasse Produkt

Produkt(String pBezeichnung, String pKategorie) Ein neues Objekt der Klasse wird mit den Parametern pBezeichnung und pKategorie initialisiert.

String gibBezeichnung() Die Methode liefert die gespeicherte Bezeichnung des Produkts.

String gibKategorie() Die Methode liefert die Kategorie des Produkts.

Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden. Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List() Eine leere Liste wird erzeugt.

boolean isEmpty() Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess() Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next() Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst() Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast() Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent() Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls (hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent) Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent) Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent) Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt (hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList) Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove() Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false), bleibt die Liste unverändert.

Die Klasse DatabaseConnector

Ein Objekt der Klasse DatabaseConnector ermöglicht die Abfrage und Manipulation einer relationalen Datenbank. Beim Erzeugen des Objekts wird eine Datenbankverbindung aufgebaut, sodass anschließend SQL-Anweisungen an diese Datenbank gerichtet werden können.

Dokumentation der Klasse DatabaseConnector

DatabaseConnector(String pIP, int pPort, String pDatabase, String pUsername, String pPassword) Ein Objekt vom Typ DatabaseConnector wird erstellt, und eine Verbindung zur Datenbank wird aufgebaut. Mit den Parametern pIP und pPort werden die IP-Adresse und die Port-Nummer übergeben, unter denen die Datenbank mit Namen pDatabase zu erreichen ist. Mit den Parametern pUsername und pPassword werden Benutzername und Passwort für die Datenbank übergeben.

void executeStatement(String pSQLStatement) Der Auftrag schickt den im Parameter pSQLStatement enthaltenen SQL-Befehl an die Datenbank ab. Handelt es sich bei pSQLStatement um einen SQL-Befehl, der eine Ergebnismenge liefert, so kann dieses Ergebnis anschließend mit der Methode getCurrentQueryResult abgerufen werden.

QueryResult getCurrentQueryResult() Die Anfrage liefert das Ergebnis des letzten mit der Methode executeStatement an die Datenbank geschickten SQL-Befehls als Objekt vom Typ QueryResult zurück. Wurde bisher kein SQL-Befehl abgeschickt oder ergab der letzte Aufruf von executeStatement keine Ergebnismenge (z. B. bei einem INSERT-Befehl oder einem Syntaxfehler), so wird null geliefert.

String getErrorMessage() Die Anfrage liefert null oder eine Fehlermeldung, die sich jeweils auf die letzte zuvor ausgeführte Datenbankoperation bezieht.

void close() Die Datenbankverbindung wird geschlossen.

Die Klasse QueryResult

Ein Objekt der Klasse QueryResult stellt die Ergebnistabelle einer Datenbankanfrage mit Hilfe der Klasse DatabaseConnector dar. Objekte dieser Klasse werden nur von der Klasse DatabaseConnector erstellt. Die Klasse verfügt über keinen öffentlichen Konstruktor.

Dokumentation der Klasse QueryResult

String[][] getData() Die Anfrage liefert die Einträge der Ergebnistabelle als zweidimensionales Feld vom Typ String. Der erste Index des Feldes stellt die Zeile und der zweite die Spalte dar (d. h. String[zeile][spalte]).

String[] getColumnNames() Die Anfrage liefert die Bezeichner der Spalten der Ergebnistabelle als Feld vom Typ String zurück.

String[] getColumnTypes() Die Anfrage liefert die Typenbezeichnung der Spalten der Ergebnistabelle als Feld vom Typ String zurück. Die Bezeichnungen entsprechen den Angaben in der Datenbank.

int getRowCount() Die Anfrage liefert die Anzahl der Zeilen der Ergebnistabelle als int.

int getColumnCount() Die Anfrage liefert die Anzahl der Spalten der Ergebnistabelle als int.

e) Im Rahmen einer Werbeaktion beabsichtigt das Unternehmen, eine zusätzliche Funktion einzuführen: Die „Liste des Tages“ soll öffentlich gezeigt werden. Hierfür wird aus dem gesamten Datenbestand eine besonders interessante oder ungewöhnliche Einkaufsliste herausgegriffen. Selbstverständlich wird nicht bekannt gegeben, welcher Benutzerin bzw. welchem Benutzer die Liste zugeordnet ist.

1.

Beurteilen Sie, inwiefern sich die Einkaufslisten im gegebenen Entity-Relationship-Modell als personenbezogene Daten einstufen lassen.

2.

Beurteilen Sie das Vorhaben des Unternehmens anhand der Grundprinzipien des Datenschutzes.

Aufgabe 4 - Endliche Automaten · Endliche Automaten

Aufgabenstellung: Analyse von Schienenanlagen einer Modelleisenbahn

Leonard besucht einen Informatikkurs und plant, nach dem Abitur Informatik zu studieren. Beim Aufräumen des Dachbodens, worum ihn seine Eltern gebeten haben, entdeckt er seine alte Eisenbahn, mit der er in der Kindheit oft gespielt hat. Ihm fällt ein, dass er stets eine sinnvolle Schienenanlage bauen wollte, auf der die Eisenbahn entweder im Kreis fährt oder die an beiden Enden durch Prellböcke abgeschlossen ist. Mit seinem Wissen aus der theoretischen Informatik will Leonard untersuchen, ob eine Schienenanlage sinnvoll aufgebaut ist. Um die Analyse überschaubar zu halten, nutzt er zunächst nur die folgenden Bauteile.

Ein endlicher Automat soll überprüfen, ob eine Schienenanlage sinnvoll aufgebaut ist.

Hierfür fügt er die Bauteil-IDs zu Wörtern zusammen, die jeweils eine Schienenanlage repräsentieren. So wird beispielsweise eine Schienenanlage, die aus zwei Prellböcken und einer dazwischenliegenden Brücke besteht, durch das Wort p1b2p dargestellt.

Leonard entwickelt das in Abbildung 2 dargestellte Zustandsübergangsdiagramm eines deterministischen endlichen Automaten A zum Überprüfen von Schienenanlagen:

Im weiteren Verlauf kommen keine Brücken und damit auch keine Auf- und Abfahrten mehr vor, stattdessen werden zusätzlich 90°-Kurvenelemente verwendet:

Anhang: Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden.

Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List()

Eine leere Liste wird erzeugt.

boolean isEmpty()

Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess()

Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next()

Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst()

Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast()

Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls ( hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent)

Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt ( hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt ( hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt ( hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList)

Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr ( hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt ( hasAccess() == false), bleibt die Liste unverändert.

Teilaufgabe a)

Erläutern Sie, über welche Eigenschaften diejenigen Schienenanlagen verfügen, die den vom Automaten A akzeptierten Wörtern entsprechen.

Ermitteln Sie sämtliche Wörter minimaler Länge, die vom Automaten A akzeptiert werden und in denen jede Bauteil-ID mindestens einmal vorkommt.

Erläutern Sie, was der Zustand q1q_1 im Sachzusammenhang bedeutet.

Teilaufgabe b)

Das Wort pp gehört zur Sprache LAL_A des Automaten A (vgl. Abbildung 1). Die zum Wort pp gehörende Schienenanlage ist aber nicht sinnvoll.

Begründen Sie im Sachzusammenhang, weshalb die zu pp gehörende Schienenanlage nicht sinnvoll ist.

Modifizieren Sie das Zustandsübergangsdiagramm in Abbildung 2 derart, dass der zugehörige deterministische endliche Automat genau die Wörter der Sprache LAL_A außer dem Wort pp akzeptiert.

Aufgabe 4 - Grammatiken, Kellerautomaten und Gren… · Grammatiken, Kellerautomaten und Grenzen endlicher Automaten

Aufgabenstellung: Analyse von Schienenanlagen einer Modelleisenbahn

Leonard besucht einen Informatikkurs und plant, nach dem Abitur Informatik zu studieren. Beim Aufräumen des Dachbodens, worum ihn seine Eltern gebeten haben, entdeckt er seine alte Eisenbahn, mit der er in der Kindheit oft gespielt hat. Ihm fällt ein, dass er stets eine sinnvolle Schienenanlage bauen wollte, auf der die Eisenbahn entweder im Kreis fährt oder die an beiden Enden durch Prellböcke abgeschlossen ist. Mit seinem Wissen aus der theoretischen Informatik will Leonard untersuchen, ob eine Schienenanlage sinnvoll aufgebaut ist. Um die Analyse überschaubar zu halten, nutzt er zunächst nur die folgenden Bauteile.

Ein endlicher Automat soll überprüfen, ob eine Schienenanlage sinnvoll aufgebaut ist.

Hierfür fügt er die Bauteil-IDs zu Wörtern zusammen, die jeweils eine Schienenanlage repräsentieren. So wird beispielsweise eine Schienenanlage, die aus zwei Prellböcken und einer dazwischenliegenden Brücke besteht, durch das Wort p1b2p dargestellt.

Leonard entwickelt das in Abbildung 2 dargestellte Zustandsübergangsdiagramm eines deterministischen endlichen Automaten A zum Überprüfen von Schienenanlagen:

Im weiteren Verlauf kommen keine Brücken und damit auch keine Auf- und Abfahrten mehr vor, stattdessen werden zusätzlich 90°-Kurvenelemente verwendet:

Anhang: Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden.

Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List()

Eine leere Liste wird erzeugt.

boolean isEmpty()

Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess()

Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next()

Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst()

Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast()

Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls ( hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent)

Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt ( hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt ( hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt ( hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList)

Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr ( hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt ( hasAccess() == false), bleibt die Liste unverändert.

Ab jetzt kommen keine Brücken und damit auch keine Auf- und Abfahrten mehr zum Einsatz; stattdessen werden zusätzlich 90°-Kurvenelemente verwendet:

c)

Die Sprache LGL_G wird von der nachstehenden Grammatik GG erzeugt:

Startsymbol:

SS

Terminalsymbole:

{g, r, l, p}\{\text{g},\ \text{r},\ \text{l},\ \text{p}\}

Nichtterminalsymbole:

{S, G, K}\{S,\ G,\ K\}

Produktionen:

{ S→pKp∣pGp,\{\ S \to \text{p}K\text{p} \mid \text{p}G\text{p},

{ K→rGl∣lGr,\phantom{\{}\ K \to \text{r}G\text{l} \mid \text{l}G\text{r},

{ G→gG∣ε }\phantom{\{}\ G \to \text{g}G \mid \varepsilon\ \}

Wort 1:

Wort 2:

Wort 3:

d)

Manche der kreisförmigen Schienenanlagen erinnern Leonard an „Ovale“. Ein „Oval“ entsteht folgendermaßen: Zuerst werden zwei Rechtskurven gebaut, danach eine bestimmte Anzahl nn gerader Gleisstücke, anschließend erneut zwei Rechtskurven und am Ende wiederum nn gerade Gleisstücke.

Leonard möchte einen deterministischen endlichen Automaten erstellen, der erkennt, ob eine geplante Schienenanlage ein „Oval“ darstellt. Leonard hat beliebig viele Bauteile zur Verfügung.

Aufgabe 4 - Algorithmen auf Feldern und linearen… · Algorithmen auf Feldern und linearen Listen

Aufgabenstellung: Analyse von Schienenanlagen einer Modelleisenbahn

Leonard besucht einen Informatikkurs und plant, nach dem Abitur Informatik zu studieren. Beim Aufräumen des Dachbodens, worum ihn seine Eltern gebeten haben, entdeckt er seine alte Eisenbahn, mit der er in der Kindheit oft gespielt hat. Ihm fällt ein, dass er stets eine sinnvolle Schienenanlage bauen wollte, auf der die Eisenbahn entweder im Kreis fährt oder die an beiden Enden durch Prellböcke abgeschlossen ist. Mit seinem Wissen aus der theoretischen Informatik will Leonard untersuchen, ob eine Schienenanlage sinnvoll aufgebaut ist. Um die Analyse überschaubar zu halten, nutzt er zunächst nur die folgenden Bauteile.

Ein endlicher Automat soll überprüfen, ob eine Schienenanlage sinnvoll aufgebaut ist.

Hierfür fügt er die Bauteil-IDs zu Wörtern zusammen, die jeweils eine Schienenanlage repräsentieren. So wird beispielsweise eine Schienenanlage, die aus zwei Prellböcken und einer dazwischenliegenden Brücke besteht, durch das Wort p1b2p dargestellt.

Leonard entwickelt das in Abbildung 2 dargestellte Zustandsübergangsdiagramm eines deterministischen endlichen Automaten A zum Überprüfen von Schienenanlagen:

Im weiteren Verlauf kommen keine Brücken und damit auch keine Auf- und Abfahrten mehr vor, stattdessen werden zusätzlich 90°-Kurvenelemente verwendet:

Anhang: Die generische Klasse List

Objekte der generischen Klasse List verwalten beliebig viele, linear angeordnete Objekte vom Typ ContentType. Auf höchstens ein Listenobjekt, aktuelles Objekt genannt, kann jeweils zugegriffen werden. Wenn eine Liste leer ist, vollständig durchlaufen wurde oder das aktuelle Objekt am Ende der Liste gelöscht wurde, gibt es kein aktuelles Objekt. Das erste oder das letzte Objekt einer Liste kann durch einen Auftrag zum aktuellen Objekt gemacht werden. Außerdem kann das dem aktuellen Objekt folgende Listenobjekt zum neuen aktuellen Objekt werden.

Das aktuelle Objekt kann gelesen, verändert oder gelöscht werden. Außerdem kann vor dem aktuellen Objekt ein Listenobjekt eingefügt werden.

Dokumentation der Klasse List<ContentType>

List()

Eine leere Liste wird erzeugt.

boolean isEmpty()

Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält, sonst liefert sie den Wert false.

boolean hasAccess()

Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst liefert sie den Wert false.

void next()

Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert false.

void toFirst()

Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

void toLast()

Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles Objekt. Ist die Liste leer, geschieht nichts.

ContentType getContent()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt zurückgegeben. Andernfalls ( hasAccess() == false) gibt die Anfrage den Wert null zurück.

void setContent(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true) und pContent ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst bleibt die Liste unverändert.

void append(ContentType pContent)

Ein neues Objekt pContent wird am Ende der Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt ( hasAccess() == false). Falls pContent gleich null ist, bleibt die Liste unverändert.

void insert(ContentType pContent)

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird ein neues Objekt pContent vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt gibt ( hasAccess() == false), wird pContent in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt ( hasAccess() == false) und die Liste nicht leer ist oder pContent == null ist, bleibt die Liste unverändert.

void concat(List<ContentType> pList)

Die Liste pList wird an die Liste angehängt. Anschließend wird pList eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls es sich bei der Liste und pList um dasselbe Objekt handelt, pList == null oder eine leere Liste ist, bleibt die Liste unverändert.

void remove()

Falls es ein aktuelles Objekt gibt ( hasAccess() == true), wird das aktuelle Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, gibt es kein aktuelles Objekt mehr ( hasAccess() == false). Wenn die Liste leer ist oder es kein aktuelles Objekt gibt ( hasAccess() == false), bleibt die Liste unverändert.

e) Leonard programmiert gern und möchte deshalb eine Methode schreiben, die sämtliche Wörter erzeugt, die mit rr beginnen und „Ovale“ darstellen. Die Methode erhält einen Parameter pMax, der angibt, wie viele gerade Gleisstücke höchstens jeweils zwischen zwei Halbkreisen eingebaut werden dürfen.

Beispiel: Bei pMax = 2 müssen demnach Wörter für die drei „Ovale“ erzeugt werden, die null, ein oder zwei Geradenstücke zwischen den Halbkreisen aufweisen:

Die Methode ermittleOvalSprache der Klasse Sprachengenerator soll die erzeugten Wörter als lineare Liste von Zeichenketten zurückliefern und besitzt diesen Methodenkopf:

public List<String> ermittleOvalSprache(int pMax) 1.

2.

Du kannst auch nach Themen lernen

Übe ein Thema mit gemischten Aufgaben aus den Prüfungen aller Jahre.

Alle 10 Themen ansehen

Andere Prüfungen 2021

GK · Haupttermin · Weiterbildungskolleg (2021) · GK · Nachtermin (2021) · LK · Haupttermin (2021) · LK · Nachtermin (2021)