Abitur NRW Informatik 2021 · GK · Haupttermin · Weiterbildungskolleg

Abiturprüfung Informatik in Nordrhein-Westfalen 2021, GK · Haupttermin · Weiterbildungskolleg: 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 · Objektorientierte Modellierung mit Implementationsdiagrammen

Aufgabenstellung:

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

Dem Kurs stehen hierfür Daten von Wetterstationen aus ganz Deutschland zur Verfügung, 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 die Messwertart, der Messwert und der Zeitpunkt abgelegt (vgl. Abbildung 1).

Das nachstehende Implementationsdiagramm zeigt einen ersten Modellierungsentwurf zur Verwaltung der Wetterdaten. Die Klassendokumentationen sind im Anhang zu finden.

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<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.

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 Datensammlungen der Wetterstationen und der Messungen jeweils als lineare Liste statt als Feld (Array) umzusetzen. [5 Punkte]

d)

Nachdem der erste Prototyp der Software getestet wurde, wird klar, dass das Projekt erweitert werden muss, um wirklich aussagekräftige Ergebnisse zu liefern. Folgende Anforderungen sollen zusätzlich 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 oben aufgeführten 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: Unveränderte Klassen, Methoden und Attribute aus dem Implementationsdiagramm in Abbildung 2 müssen nicht dargestellt bzw. angegeben werden. [13 Punkte]

e)

Ein Schüler schlägt vor, dass man die Klassen Wetterstation und Messung durch eine neue Klasse Wetteraufzeichnung ersetzen sollte. Im Folgenden werden Beispieldaten für Wetteraufzeichnungen dargestellt:

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 · (noch keine Messungen vorhanden)

Die Klasse Wetterdatenverwaltung würde dann eine Liste von Objekten der Klasse Wetteraufzeichnung verwalten.

Der Schüler behauptet, dass man aus dieser einen Liste von Wetteraufzeichnungen schließlich auch alle Informationen auslesen könne, sein Vorschlag einfacher zu implementieren sei und sonst keine nennenswerten Nachteile habe.

Begründen Sie ausgehend von der Behauptung des Schülers, weshalb der Alternativvorschlag nicht angenommen werden sollte. [7 Punkte]

Aufgabe 1 - Algorithmen auf linearen Listen · 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.

Dem Kurs stehen hierfür Daten von Wetterstationen aus ganz Deutschland zur Verfügung, 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 die Messwertart, der Messwert und der Zeitpunkt abgelegt (vgl. Abbildung 1).

Das nachstehende Implementationsdiagramm zeigt einen ersten Modellierungsentwurf zur Verwaltung der Wetterdaten. Die Klassendokumentationen sind im Anhang zu finden.

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<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.

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.

b)

Als das Projekt bereits ein gutes Stück vorangekommen ist, stößt eine Schülerin in der Klasse Wetterdatenverwaltung auf die nicht dokumentierte Methode ermittleEtwas.

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 Werte die folgenden Methodenaufrufe zurückgeben:

c)

In die Klasse Wetterstation soll zusätzlich die im Anhang dokumentierte Methode ermittleMaximum aufgenommen werden. Ihr Methodenkopf lautet:

public Double ermittleMaximum(String pMesswertart)

public Double ermittleMaximum(String pMesswertart) {

}

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

Aufgabenstellung: Scooter-Verleih

In Köln bietet ein neu gegründetes Startup elektrische Roller, sogenannte Scooter, zur Miete an. Jeder Scooter besitzt einen GPS-Empfänger und sendet per Internetverbindung jede Minute seine aktuelle Position (Standort) und seinen Batteriestand (Akkuladung) an den Server des Unternehmens. Damit sich die Entfernung eines Scooters von der Firmenzentrale einfach bestimmen lässt, geben die Scooter ihre Position relativ zur Firmenzentrale an (Koordinatenursprung). Auf dem Server wird jeweils die zuletzt gemeldete Position als Punkt in einem Koordinatensystem abgelegt. Abbildung 1 stellt die aktuelle Lage in der näheren Umgebung der Firmenzentrale dar.

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

Bisher setzt das Unternehmen die vier in Abbildung 1 gezeigten Scooter ein. Der daraus entstehende binäre Suchbaum ist in Abbildung 2 zu sehen.

Die Software des Unternehmens speichert außer den Scooterdaten auch die Daten der Kundinnen und Kunden, die Scooter ausleihen wollen. Vereinfachend wird jede Kundin und jeder Kunde im Modell nur durch eine eindeutige E-Mail-Adresse sowie eine Kreditkartennummer für die Abrechnung beschrieben.

Grundlage der Softwareentwicklung 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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. 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.

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 / Konstruktor · 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)

a.1)

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 durch das Einfügen entsteht, grafisch dar.

a.2)

Stellen Sie denjenigen 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 } Der binäre Suchbaum alleScooter beinhalte den Suchbaum aus Abbildung 2 mit den Suchschlüsseln der Scooter aus Abbildung 1. Die öffentliche Methode liefereEtwas werde mit dem Parameter pWert = 80 aufgerufen.

c.1)

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

c.2)

Erläutern Sie, wie die private Methode arbeitet.

c.3)

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 wurden. Dafür setzt das Unternehmen eine Drohne ein, die abends alle Scooter anfliegt und von jedem ein Foto an die Firmenzentrale sendet. Sobald alle Scooter fotografiert sind, kehrt die Drohne zur Firmenzentrale zurück.

Ein Praktikant empfiehlt, die Scooter erst aufsteigend nach ihrer Entfernung von der Firmenzentrale zu sortieren und in dieser Reihenfolge in einer Liste abzulegen. Anhand dieser Liste könnte die Drohne die Scooter nacheinander anfliegen und fotografieren.

e.1)

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.

e.2)

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

e.3)

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

Aufgabe 2 - Objektorientierte Modellierung · Objektorientierte Modellierung mit Implementationsdiagrammen

Aufgabenstellung: Scooter-Verleih

In Köln bietet ein neu gegründetes Startup elektrische Roller, sogenannte Scooter, zur Miete an. Jeder Scooter besitzt einen GPS-Empfänger und sendet per Internetverbindung jede Minute seine aktuelle Position (Standort) und seinen Batteriestand (Akkuladung) an den Server des Unternehmens. Damit sich die Entfernung eines Scooters von der Firmenzentrale einfach bestimmen lässt, geben die Scooter ihre Position relativ zur Firmenzentrale an (Koordinatenursprung). Auf dem Server wird jeweils die zuletzt gemeldete Position als Punkt in einem Koordinatensystem abgelegt. Abbildung 1 stellt die aktuelle Lage in der näheren Umgebung der Firmenzentrale dar.

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

Bisher setzt das Unternehmen die vier in Abbildung 1 gezeigten Scooter ein. Der daraus entstehende binäre Suchbaum ist in Abbildung 2 zu sehen.

Die Software des Unternehmens speichert außer den Scooterdaten auch die Daten der Kundinnen und Kunden, die Scooter ausleihen wollen. Vereinfachend wird jede Kundin und jeder Kunde im Modell nur durch eine eindeutige E-Mail-Adresse sowie eine Kreditkartennummer für die Abrechnung beschrieben.

Grundlage der Softwareentwicklung 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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. 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.

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 / Konstruktor · 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 sowie das Interface ComparableContent miteinander in Beziehung stehen.

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 als Datenstruktur ausreichend ist.

[8 Punkte]

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

Aufgabenstellung: Scooter-Verleih

In Köln bietet ein neu gegründetes Startup elektrische Roller, sogenannte Scooter, zur Miete an. Jeder Scooter besitzt einen GPS-Empfänger und sendet per Internetverbindung jede Minute seine aktuelle Position (Standort) und seinen Batteriestand (Akkuladung) an den Server des Unternehmens. Damit sich die Entfernung eines Scooters von der Firmenzentrale einfach bestimmen lässt, geben die Scooter ihre Position relativ zur Firmenzentrale an (Koordinatenursprung). Auf dem Server wird jeweils die zuletzt gemeldete Position als Punkt in einem Koordinatensystem abgelegt. Abbildung 1 stellt die aktuelle Lage in der näheren Umgebung der Firmenzentrale dar.

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

Bisher setzt das Unternehmen die vier in Abbildung 1 gezeigten Scooter ein. Der daraus entstehende binäre Suchbaum ist in Abbildung 2 zu sehen.

Die Software des Unternehmens speichert außer den Scooterdaten auch die Daten der Kundinnen und Kunden, die Scooter ausleihen wollen. Vereinfachend wird jede Kundin und jeder Kunde im Modell nur durch eine eindeutige E-Mail-Adresse sowie eine Kreditkartennummer für die Abrechnung beschrieben.

Grundlage der Softwareentwicklung 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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 / Konstruktor · 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. 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.

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 / Konstruktor · 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 an, die folgenden Methodenkopf hat:

public void ausleihen(String pEMailAdresse, int pScooternummer)

Die Methode soll den Ausleihvorgang abwickeln. Ihre Dokumentation befindet sich in der Anlage.

Implementieren Sie die Methode gemäß ihrer Dokumentation.

Aufgabe 3 - Datenbankmodellierung · Datenbankmodellierung und Normalisierung

Aufgabenstellung: Einkaufslisten-App

Ein Unternehmen plant die Entwicklung einer App, mit der mehrere Einkaufslisten angelegt und verwaltet werden können.

Wer die App nutzen will, muss sich mit dem eigenen Namen, einem eindeutigen Benutzernamen und einem Passwort registrieren. Dabei ist die Zustimmung erforderlich, dass die angegebenen Daten zur Erbringung 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 auch eigene neue Produkte ergänzt werden.

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

Aus der Modellierung ergibt sich das nachstehende Datenbankschema. Im Anhang stehen Beispieldatensätze zu diesem Schema.

Auf den Endgeräten der Nutzenden soll eine Software laufen, die die Daten der angemeldeten Person aus einer Datenbank lädt und sie für den Einkauf im Geschäft passend anzeigt. Dafür liegt das folgende Teilmodell vor:

Anlage: Beispieldaten

Einkaufsliste

ID

Titel

Benutzername

14 · Salatliste · Linus

15 · Biomarkt · FabBen

16 · Hamstern · FabBen

17 · Einkaufen · Linus

18 · Geburtstagsfeier · FabBen

19 · Biomarkt · JaStIn

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.

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

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: Dokumentationen 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 a)

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 zugeordnet ist und nicht dem Relationenschema Produkt.

[8 Punkte]

Teilaufgabe d)

d)

Erläutern Sie die Assoziationen, die in Abbildung 4 zu sehen sind, im Sachkontext.

Vergleichen Sie das Implementationsdiagramm in Abbildung 4 mit dem Entity-Relationship-Diagramm in Abbildung 2 und erläutern Sie Gemeinsamkeiten sowie Unterschiede hinsichtlich der Daten, die in der App bzw. in der Datenbank modelliert werden.

Hinweis: Ziehen Sie hierfür zusätzlich die Dokumentationen im Anhang heran.

[13 Punkte]

Aufgabe 3 - SQL-Abfragen · SQL-Abfragen

Aufgabenstellung: Einkaufslisten-App

Ein Unternehmen plant die Entwicklung einer App, mit der mehrere Einkaufslisten angelegt und verwaltet werden können.

Wer die App nutzen will, muss sich mit dem eigenen Namen, einem eindeutigen Benutzernamen und einem Passwort registrieren. Dabei ist die Zustimmung erforderlich, dass die angegebenen Daten zur Erbringung 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 auch eigene neue Produkte ergänzt werden.

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

Aus der Modellierung ergibt sich das nachstehende Datenbankschema. Im Anhang stehen Beispieldatensätze zu diesem Schema.

Auf den Endgeräten der Nutzenden soll eine Software laufen, die die Daten der angemeldeten Person aus einer Datenbank lädt und sie für den Einkauf im Geschäft passend anzeigt. Dafür liegt das folgende Teilmodell vor:

Anlage: Beispieldaten

Einkaufsliste

ID

Titel

Benutzername

14 · Salatliste · Linus

15 · Biomarkt · FabBen

16 · Hamstern · FabBen

17 · Einkaufen · Linus

18 · Geburtstagsfeier · FabBen

19 · Biomarkt · JaStIn

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.

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

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: Dokumentationen 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)

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

Entwerfen Sie zu jeder der genannten Anfragen eine 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 derjenigen 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 geordnet sein.

iii.

Für den Benutzer mit dem Benutzernamen Linus sollen die Kategorien bestimmt werden, aus denen Produkte auf seinen Listen stehen. Zusätzlich ist für jede dieser Kategorien die Gesamtsumme der Mengenangaben zu berechnen.

Teilaufgabe c)

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)

c.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.

c.2

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

c.3

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

c.4

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

Aufgabe 3 - Datenschutz · Datenschutz und Datensicherheit

Aufgabenstellung: Einkaufslisten-App

Ein Unternehmen plant die Entwicklung einer App, mit der mehrere Einkaufslisten angelegt und verwaltet werden können.

Wer die App nutzen will, muss sich mit dem eigenen Namen, einem eindeutigen Benutzernamen und einem Passwort registrieren. Dabei ist die Zustimmung erforderlich, dass die angegebenen Daten zur Erbringung 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 auch eigene neue Produkte ergänzt werden.

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

Aus der Modellierung ergibt sich das nachstehende Datenbankschema. Im Anhang stehen Beispieldatensätze zu diesem Schema.

Auf den Endgeräten der Nutzenden soll eine Software laufen, die die Daten der angemeldeten Person aus einer Datenbank lädt und sie für den Einkauf im Geschäft passend anzeigt. Dafür liegt das folgende Teilmodell vor:

Anlage: Beispieldaten

Einkaufsliste

ID

Titel

Benutzername

14 · Salatliste · Linus

15 · Biomarkt · FabBen

16 · Hamstern · FabBen

17 · Einkaufen · Linus

18 · Geburtstagsfeier · FabBen

19 · Biomarkt · JaStIn

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.

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

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: Dokumentationen 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 will das Unternehmen eine zusätzliche Funktion einführen: Die „Liste des Tages“ wird öffentlich gemacht. Hierfür wird aus dem gesamten Datenbestand eine besonders interessante oder ungewöhnliche Einkaufsliste herausgesucht. Selbstverständlich wird dabei nicht bekannt gegeben, welcher Benutzerin bzw. welchem Benutzer die Liste zugeordnet ist.

Aufgabe 4 - Endliche Automaten · Endliche Automaten

Aufgabenstellung:

Leonard besucht einen Informatikkurs und plant, nach dem Abitur Informatik zu studieren. Beim Aufräumen des Dachbodens, wozu ihn seine Eltern auffordern, stößt er auf seine alte Modelleisenbahn, mit der er als Kind oft gespielt hat. Er weiß noch, dass er stets eine sinnvolle Schienenanlage bauen wollte, auf der die Bahn entweder im Kreis fährt oder an Prellböcken endet. Mit seinem Wissen aus der theoretischen Informatik will Leonard untersuchen, ob eine Schienenanlage sinnvoll aufgebaut ist. Um die Untersuchung überschaubar zu halten, nutzt er zunächst nur die folgenden Bauteile.

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

Hierfür reiht er die Bauteil-IDs zu Wörtern aneinander, die jeweils eine Schienenanlage repräsentieren. Eine Anlage aus zwei Prellböcken mit einer Brücke dazwischen wird zum Beispiel durch das Wort p1b2p beschrieben.

Zur Überprüfung von Schienenanlagen entwirft Leonard einen deterministischen endlichen Automaten A, dessen Zustandsübergangsdiagramm in Abbildung 2 zu sehen ist:

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 ( 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.

a)

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

Ermitteln Sie sämtliche kürzestmöglichen Wörter, 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.

[9 Punkte]

b)

Das Wort pppp gehört zur Sprache LAL_A des Automaten A (vgl. Abbildung 1). Dennoch ist die Schienenanlage, die zum Wort pppp gehört, nicht sinnvoll.

Begründen Sie im Sachzusammenhang, weshalb die zum Wort pppp gehörende Schienenanlage nicht sinnvoll ist.

Modifizieren Sie das Zustandsübergangsdiagramm in Abbildung 2 derart, dass der zugehörige deterministische endliche Automat jedes Wort der Sprache LAL_A akzeptiert, nur das Wort pppp nicht.

[8 Punkte]

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

Aufgabenstellung:

Leonard besucht einen Informatikkurs und plant, nach dem Abitur Informatik zu studieren. Beim Aufräumen des Dachbodens, wozu ihn seine Eltern auffordern, stößt er auf seine alte Modelleisenbahn, mit der er als Kind oft gespielt hat. Er weiß noch, dass er stets eine sinnvolle Schienenanlage bauen wollte, auf der die Bahn entweder im Kreis fährt oder an Prellböcken endet. Mit seinem Wissen aus der theoretischen Informatik will Leonard untersuchen, ob eine Schienenanlage sinnvoll aufgebaut ist. Um die Untersuchung überschaubar zu halten, nutzt er zunächst nur die folgenden Bauteile.

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

Hierfür reiht er die Bauteil-IDs zu Wörtern aneinander, die jeweils eine Schienenanlage repräsentieren. Eine Anlage aus zwei Prellböcken mit einer Brücke dazwischen wird zum Beispiel durch das Wort p1b2p beschrieben.

Zur Überprüfung von Schienenanlagen entwirft Leonard einen deterministischen endlichen Automaten A, dessen Zustandsübergangsdiagramm in Abbildung 2 zu sehen ist:

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 ( 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 stehen zusätzlich 90°-Kurvenelemente zur Verfügung:

c)

Die Sprache LGL_G wird von der nachstehenden Grammatik GG erzeugt:

Startsymbol: SS

Terminalsymbole: {g, r, l, p}\{g,\ r,\ l,\ p\}

Nichtterminalsymbole: {S, G, K}\{S,\ G,\ K\}

Produktionen:

S→pKp∣pGpS \rightarrow pKp \mid pGp,

K→rGl∣lGrK \rightarrow rGl \mid lGr,

G→gG∣εG \rightarrow gG \mid \varepsilon

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 schließlich noch einmal nn gerade Gleisstücke.

Leonard möchte einen deterministischen endlichen Automaten erstellen, der feststellt, ob eine geplante Schienenanlage ein „Oval“ ist. Dabei stehen ihm beliebig viele Bauteile zur Verfügung.

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

Aufgabenstellung:

Leonard besucht einen Informatikkurs und plant, nach dem Abitur Informatik zu studieren. Beim Aufräumen des Dachbodens, wozu ihn seine Eltern auffordern, stößt er auf seine alte Modelleisenbahn, mit der er als Kind oft gespielt hat. Er weiß noch, dass er stets eine sinnvolle Schienenanlage bauen wollte, auf der die Bahn entweder im Kreis fährt oder an Prellböcken endet. Mit seinem Wissen aus der theoretischen Informatik will Leonard untersuchen, ob eine Schienenanlage sinnvoll aufgebaut ist. Um die Untersuchung überschaubar zu halten, nutzt er zunächst nur die folgenden Bauteile.

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

Hierfür reiht er die Bauteil-IDs zu Wörtern aneinander, die jeweils eine Schienenanlage repräsentieren. Eine Anlage aus zwei Prellböcken mit einer Brücke dazwischen wird zum Beispiel durch das Wort p1b2p beschrieben.

Zur Überprüfung von Schienenanlagen entwirft Leonard einen deterministischen endlichen Automaten A, dessen Zustandsübergangsdiagramm in Abbildung 2 zu sehen ist:

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 ( 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 den Parameter pMax, der angibt, wie viele gerade Gleisstücke höchstens jeweils zwischen zwei Halbkreisen verbaut werden dürfen.

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

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.

Entwickeln Sie ein algorithmisches Verfahren für die Methode ermittleOvalSprache, das der oben angegebenen Dokumentation entspricht. [4 Punkte]

2.

Implementieren Sie die Methode ermittleOvalSprache. [7 Punkte]

public List<String> ermittleOvalSprache(int pMax) {

}

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 (2021) · GK · Nachtermin (2021) · LK · Haupttermin (2021) · LK · Nachtermin (2021)