Übungsaufgaben zu objektorientierten Algorithmen: Methoden über Objektlisten

https://bildung.social/@oerinformatik/

https://oer-informatik.de/algorithmen-objektorientiert-uebungsaufgaben

Objektorientierte Algorithmen, Pseudocode, Objektlisten, Lineare Suche, Schreibtischtest, Polymorphie, UML-Klassendiagramm, Übungsaufgaben, Prüfungsvorbereitung

tl/dr; (Bearbeitungszeit insgesamt 130 min, mehrere Aufgaben): Fünf Übungsaufgaben, in denen Du Methoden über Listen und Arrays von Objekten in Pseudocode schreibst: einen Monatsbericht mit Kennzahlen und fehlenden Werten erstellen, Barcamp-Anmeldungen aus einer CSV-Datei importieren und Dubletten erkennen, Mitfahrangebote filtern, sortieren und anfragen, Absatz und Wochentagsumsatz mit Map und Array auswerten, einen fehlerhaften Entwurf per Schreibtischtest prüfen, eine Haltephase im Ofenprotokoll finden sowie eine seitenweise Schnittstelle, polymorphe Statusmeldungen, eine Rundenplanung und eine Raumbelegung für ein Barcamp bearbeiten. Alle Lösungen sind ausgeblendet, in vier Pseudocode-Notationen umschaltbar und mit Punkteverteilung versehen [AI-Assisted]. (Zuletzt geändert am 28.10.2026)

Diese Übungsaufgaben gehören zum Artikel Objektorientierte Algorithmen: Methoden über Objektlisten. Sie setzen voraus, dass Du Algorithmen in Pseudocode notieren und UML-Klassendiagramme lesen kannst.

Hinweise zur Bearbeitung: Als FIA oder FIDP musst Du zur Teil-2-Prüfung Aufgaben auf Kernkompetenz-Ebene lösen können, das sind Aufgabe 2.1 und Aufgabe 2.2. Von FIA wird zusätzlich erwartet, dass ihnen Aufgaben auf Profilkompetenz-Ebene (Aufgabe 3.1, Aufgabe 3.2 und Aufgabe 3.3) keine Probleme bereiten. Schreibe Deine Lösung zuerst auf Papier, bevor Du die Beispiellösung aufklappst.

Du kannst in einer der vier Pseudocode-Notationen antworten; die Beispiellösungen stehen in allen vier zur Auswahl. Die Notationen sind im Artikel Algorithmen mit Pseudocode dokumentieren beschrieben. So sieht eine Schleife über eine Liste von Objekten aus:

für jedes a in aktivitaeten
    summe := summe + a.getZusagen()
Ende für

Für Listen gibt es in JANA und beiden Pascal-Varianten die Methoden add(t) (anhängen), add(i, t) (an Position i einfügen), size() und get(i) (erste Position: 0); in Pseudo-Python sind es append(t), insert(i, t), len(liste) und liste[i]. Ein Struktogramm oder eine echte Programmiersprache ist ebenfalls richtig. Auf private Attribute greifst Du nur über Getter und Setter zu. Andere fachlich richtige Lösungen bekommen die volle Punktzahl.

Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?

Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.

Erstelle neue Übungsaufgaben zum Thema „Objektorientierte Algorithmen:
Methoden über Objektlisten“.

Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.

Fachliche Grundlage:
- https://oer-informatik.de/algorithmen-objektorientiert
- https://oer-informatik.de/pseudocode
- https://oer-informatik.de/uml-klassendiagramm
- https://oer-informatik.de/programmentwurfstechniken
- https://oer-informatik.de/uml-klassendiagramm-polymorphie
- Stilbeispiel: https://oer-informatik.de/algorithmen-objektorientiert-uebungsaufgaben

Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- Objektorientierte Algorithmen
- Pseudocode
- Objektlisten
- Lineare Suche
- Schreibtischtest
- Polymorphie
- UML-Klassendiagramm

Kompetenzstufe: Profilkompetenz (alternativ: Basiskompetenz, Kernkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan

Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
   abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
   zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
   Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
   Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
   Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
   danach frage.

Aufgabe 2.1: Aktivitäten eines Monats auswerten (Kernkompetenz)

(ca. 26 min Bearbeitungszeit)

In der App der Let’s Meet GmbH melden Organisator*innen nach jeder Aktivität, wie viele der Zugesagten tatsächlich gekommen sind. Geschäftsführerin Clara Neumann möchte jeden Monat einen kurzen Bericht über das Angebot sehen. Du entwickelst ihn mit Mit-Azubi Jonas Weber.

Die Aktivitäten eines Monats liegen in der Liste aktivitaeten vom Typ List<Aktivitaet>:

  • Aktivitaet hat die Attribute titel: String, plaetze: Integer, zusagen: Integer und erschienen: Integer [0..1] mit öffentlichen Gettern. erschienen ist null, solange die Organisatorin oder der Organisator nichts gemeldet hat.

  • Die Klasse Monatsbericht hat den Konstruktor Monatsbericht(ausgebucht: Integer, noShowQuote: Real, schwaechste: Aktivitaet, ohneMeldung: Integer).

Der Bericht enthält:

  • ausgebucht: die Zahl der Aktivitäten, bei denen die Zusagen die Plätze erreichen,

  • noShowQuote: den Anteil der Zusagen in Prozent, die nicht erschienen sind; berücksichtigt werden nur Aktivitäten mit Meldung, und es wird über alle diese Zusagen zusammen gerechnet,

  • schwaechste: die gemeldete Aktivität mit der kleinsten Auslastung (Erschienene geteilt durch Plätze); bei Gleichstand die zuerst gefundene, ohne gemeldete Aktivität null,

  • ohneMeldung: die Zahl der Aktivitäten ohne Meldung.

Aktivitäten im September 2026 (Auszug):

Aktivitäten im September 2026
titel plaetze zusagen erschienen
Boule im Bürgerpark 8 8 7
Thai-Kochabend 6 6 6
Lauftreff am Obersee 12 9 null
Brettspielabend 10 7 4
Radtour im Teuto 15 15 11
Fotowalk Altstadt 10 4 3
Führung Sparrenburg 20 11 null

a) Lege vor dem Programmieren die erwarteten Ergebnisse fest: Bestimme die vier Werte des Berichts für die Beispieldaten von Hand und gib für die noShowQuote den Rechenweg an. (5 Punkte)

  • ausgebucht = 3: Boule, Thai-Kochabend und Radtour (Zusagen = Plätze).

  • ohneMeldung = 2: Lauftreff und Führung.

  • noShowQuote = 22,5 %: Gemeldet sind fünf Aktivitäten mit 8 + 6 + 7 + 15 + 4 = 40 Zusagen und 7 + 6 + 4 + 11 + 3 = 31 Erschienenen. Nicht erschienen sind 9; \frac{9}{40} \cdot 100 = 22{,}5\ \%.

  • schwaechste = Fotowalk Altstadt: Auslastungen 0,875; 1,0; 0,4; 0,733; 0,3.

Je Wert 1 Punkt, Rechenweg der Quote 1 Punkt.

b) Entwickle die Methode erstelleBericht(aktivitaeten: List<Aktivitaet>): Monatsbericht. Sie soll mit einem einzigen Durchlauf durch die Liste auskommen und darf bei einer leeren Liste oder ohne gemeldete Aktivität nicht abbrechen. (16 Punkte)

Funktion erstelleBericht(aktivitaeten: List<Aktivitaet>): Monatsbericht
    ausgebucht: integer := 0
    ohneMeldung: integer := 0
    summeZusagen: integer := 0
    summeErschienen: integer := 0
    schwaechste: Aktivitaet := null
    minAuslastung: double := 0.0
    für jedes a in aktivitaeten
        wenn a.getZusagen() >= a.getPlaetze() dann
            ausgebucht := ausgebucht + 1
        Ende wenn
        wenn a.getErschienen() = null dann
            ohneMeldung := ohneMeldung + 1
        sonst
            summeZusagen := summeZusagen + a.getZusagen()
            summeErschienen := summeErschienen + a.getErschienen()
            auslastung: double := a.getErschienen() * 1.0 / a.getPlaetze()
            wenn schwaechste = null oder auslastung < minAuslastung dann
                schwaechste := a
                minAuslastung := auslastung
            Ende wenn
        Ende wenn
    Ende für
    quote: double := 0.0
    wenn summeZusagen > 0 dann
        quote := (summeZusagen - summeErschienen) * 100.0 / summeZusagen
    Ende wenn
    Rückgabe new Monatsbericht(ausgebucht, quote, schwaechste, ohneMeldung)
Ende erstelleBericht

Die Auslastung wird mit * 1.0 zur Kommazahl, sonst ergäbe die Division zweier Ganzzahlen in vielen Sprachen 0. Für die Beispieldaten liefert die Methode die Werte aus a).

Bewertung:

Baustein Punkte
Zähler, Summen und Merker vor der Schleife angelegt 2
eine Schleife über alle Aktivitäten 1
ausgebuchte Aktivitäten mit >= gezählt 2
fehlende Meldung über null erkannt und gezählt, bevor getErschienen() weiterverwendet wird 3
Summen nur über gemeldete Aktivitäten 2
schwächste Aktivität: Auslastung als Kommazahl, erster Wert berücksichtigt, Objekt gemerkt 3
Quote in Prozent, Division durch 0 abgefangen 2
Rückgabe über den Konstruktor 1

Ein Struktogramm mit denselben Bausteinen erhält die volle Punktzahl.

c) Jonas möchte die No-Show-Quote anders berechnen: erst für jede gemeldete Aktivität die Quote, dann den Durchschnitt dieser Quoten. Berechne seinen Wert für die Beispieldaten und vergleiche ihn mit dem Wert aus a). Welche Berechnung passt besser zu Claras Frage, wie viele zugesagte Plätze leer geblieben sind? (4 Punkte)

Quoten je Aktivität: Boule 12,5 %, Thai-Kochabend 0 %, Brettspielabend 42,86 %, Radtour 26,67 %, Fotowalk 25 %. Durchschnitt: \frac{12{,}5 + 0 + 42{,}86 + 26{,}67 + 25}{5} \approx 21{,}4\ \% (2 Punkte).

Die Berechnung über alle Zusagen (22,5 %) beantwortet Claras Frage direkt: Sie zählt jede leere Zusage gleich, große Aktivitäten zählen also mehr. Jonas’ Durchschnitt gewichtet jede Aktivität gleich; eine kleine Aktivität mit vier Zusagen beeinflusst ihn genauso stark wie die Radtour mit fünfzehn (2 Punkte). Sein Wert ist sinnvoll, wenn gefragt ist, wie zuverlässig eine typische Aktivität besucht wird.

d) Clara schlägt vor: „Die schwächste Aktivität nehmen wir im nächsten Monat aus dem Programm.“ Beurteile, ob der Bericht diese Entscheidung trägt, und schlage eine bessere Grundlage vor. (3 Punkte)

Die Auslastung mischt zwei Ursachen: Der Fotowalk hatte wenige Zusagen (geringes Interesse oder schlechte Sichtbarkeit in der App), aber drei von vier Zugesagten sind gekommen – die Zuverlässigkeit ist gut (1 Punkt). Ein einzelner Monat mit einem Termin ist außerdem eine sehr kleine Grundlage (1 Punkt). Besser: Zusagequote (Zusagen je Platz) und Erscheinensquote getrennt betrachten, über mehrere Monate vergleichen und die Organisator*innen nach Gründen fragen, etwa Termin oder Wetter (1 Punkt).

Aufgabe 2.2: Anmeldungen für das Barcamp importieren (Kernkompetenz)

(ca. 24 min Bearbeitungszeit)

Für das Barcamp „Lernen.Digital.Leben 2027“ am Ratz und Rübe Berufskolleg melden sich Teilnehmende, Referent*innen und Ausstellende über ein Online-Formular an. Das Formular liefert eine CSV-Datei, die regelmäßig in die Orga-Software übernommen wird. Dimitrios Papadopoulos aus der Orga-Leitung bittet Dich, die Importmethode zu schreiben.

Vorhanden sind:

  • Anmeldung mit den Attributen email, name und rolle (alle String), Gettern, Settern und dem Konstruktor Anmeldung(email: String, name: String, rolle: String).

  • Teilnehmerverwaltung mit den Attributen anmeldungen: List<Anmeldung> und protokoll: List<String>, der Methode suche(email: String): Anmeldung (liefert die Anmeldung mit dieser E-Mail-Adresse oder null) und der zu schreibenden Methode importieren(pfad: String): Integer.

  • Textdatei.liesAlleZeilen(pfad: String): List<String> (statisch) liefert alle Zeilen der Datei; die erste Zeile ist die Kopfzeile email;name;rolle.

  • Zeichenketten bieten split(trenner): String[], trim(): String (Leerzeichen am Rand entfernen), toLowerCase(): String und contains(teil): Boolean. In Pseudo-Python heißen sie split, strip, lower und teil in text. split liefert auch leere Felder, z. B. am Zeilenende.

Für den Import gilt:

  1. Eine Zeile muss genau drei Felder haben, sonst wird sie nicht übernommen und im Protokoll als „Zeile N: Feldzahl“ vermerkt (N ist die Zeilennummer in der Datei, die Kopfzeile ist Zeile 1).

  2. Die E-Mail-Adresse wird ohne Leerzeichen am Rand und in Kleinbuchstaben gespeichert. Enthält sie kein @, wird die Zeile nicht übernommen: „Zeile N: E-Mail ungültig“.

  3. Eine leere Rolle wird zu „Teilnahme“.

  4. Gibt es zur E-Mail-Adresse schon eine Anmeldung, entsteht keine neue; Name und Rolle der vorhandenen werden durch die Werte der Zeile ersetzt: „Zeile N: aktualisiert“.

importieren gibt die Zahl der neu angelegten Anmeldungen zurück.

a) In der Teilnehmerverwaltung steht bereits die Anmeldung von mia.schroeder@rrbk.example. Entscheide für jede Datenzeile der folgenden Datei, was der Import damit macht, und gib den Rückgabewert an. (6 Punkte)

email;name;rolle
mia.schroeder@rrbk.example;Mia Schröder;Referentin
 Hannah.Klein@RRBK.example ;Hannah Klein;
marco.brenner(at)webwerk.example;Marco Brenner;Teilnahme
fatma.oeztuerk@rrbk.example;Fatma Öztürk
hannah.klein@rrbk.example;Hannah Klein;Helferin
jan.peters@peters-elektro.example;Jan Peters;Aussteller
Zeile Ergebnis Begründung
2 aktualisiert, Rolle jetzt „Referentin“ Mias Adresse ist schon vorhanden (Regel 4)
3 neu: hannah.klein@rrbk.example, Rolle „Teilnahme“ Leerzeichen und Großbuchstaben bereinigt, leere Rolle ersetzt (Regeln 2 und 3)
4 nicht übernommen, „E-Mail ungültig“ kein @ (Regel 2)
5 nicht übernommen, „Feldzahl“ nur zwei Felder (Regel 1)
6 aktualisiert, Rolle jetzt „Helferin“ die Adresse wurde in Zeile 3 angelegt (Regel 4)
7 neu: Jan Peters, Rolle „Aussteller“ –

Rückgabewert: 2. Je Zeile 1 Punkt (Ergebnis mit Begründung).

b) Programmiere die Methode importieren(pfad: String): Integer. (14 Punkte)

Funktion importieren(pfad: string): integer
    zeilen: List<string> := Textdatei.liesAlleZeilen(pfad)
    neu: integer := 0
    zähle i von 1 bis zeilen.size() - 1
        felder: string[] := zeilen.get(i).split(";")
        wenn laenge(felder) <> 3 dann
            protokoll.add("Zeile " & (i + 1) & ": Feldzahl")
        sonst
            email: string := felder[0].trim().toLowerCase()
            rolle: string := felder[2].trim()
            wenn rolle = "" dann
                rolle := "Teilnahme"
            Ende wenn
            wenn nicht email.contains("@") dann
                protokoll.add("Zeile " & (i + 1) & ": E-Mail ungültig")
            sonst
                vorhanden: Anmeldung := suche(email)
                wenn vorhanden = null dann
                    anmeldungen.add(new Anmeldung(email, felder[1].trim(), rolle))
                    neu := neu + 1
                sonst
                    vorhanden.setName(felder[1].trim())
                    vorhanden.setRolle(rolle)
                    protokoll.add("Zeile " & (i + 1) & ": aktualisiert")
                Ende wenn
            Ende wenn
        Ende wenn
    Ende zähle
    Rückgabe neu
Ende importieren

Bewertung:

Baustein Punkte
Zeilen holen, Zählschleife ab Index 1 (Kopfzeile ausgelassen) 2
Zeile mit split(";") zerlegt 1
Feldzahl geprüft und protokolliert, bevor auf die Felder zugegriffen wird 2
E-Mail bereinigt (trim, toLowerCase) 2
leere Rolle ersetzt 1
E-Mail mit contains("@") geprüft und protokolliert 2
Dublette über suche erkannt, Werte per Setter ersetzt, protokolliert 2
neue Anmeldung mit Konstruktor angelegt und gezählt 1
Rückgabe der neuen Anmeldungen 1

Die Zeilennummer im Protokoll ist i + 1, weil der Index bei 0 beginnt und die Kopfzeile Zeile 1 ist.

c) Regel 4 lässt eine spätere Zeile eine vorhandene Anmeldung überschreiben. Beurteile diese Regel aus Sicht der Datenqualität und nenne eine Verbesserung. (3 Punkte)

Vorteil: Es entstehen keine Dubletten (Eindeutigkeit), und Korrekturen wie Hannahs neue Rolle kommen an (Aktualität) (1 Punkt). Nachteil: Wer eine fremde oder vertippte E-Mail-Adresse einträgt, überschreibt ohne Rückfrage die Daten einer anderen Person; ob die neue Angabe stimmt, prüft niemand (Korrektheit) (1 Punkt). Verbesserung, z. B.: Änderungen erst nach Bestätigung über einen Link an die vorhandene Adresse übernehmen oder die Zeile nur protokollieren und von der Orga freigeben lassen (1 Punkt).

d) Die Prüfung mit contains("@") lässt noch viele unbrauchbare Adressen durch. Nenne zwei solche Beispiele und formuliere eine strengere Prüfregel in Worten. (3 Punkte)

Beispiele (1 Punkt): @rrbk.example, hannah@, hannah@@rrbk.example, hannah klein@rrbk.example.

Strengere Regel (2 Punkte), z. B.: Die Adresse enthält genau ein @, davor steht mindestens ein Zeichen, dahinter ein Domainname mit mindestens einem Punkt, der nicht am Anfang oder Ende steht, und sie enthält keine Leerzeichen. Ob es das Postfach wirklich gibt, zeigt erst eine Bestätigungs-E-Mail.

Aufgabe 3.1: Mitfahrangebote vermitteln (Profilkompetenz)

(ca. 24 min Bearbeitungszeit)

Du arbeitest als Auszubildende*r im FIA-Projektteam der Mitfahr-App RatzFahrt am Ratz und Rübe Berufskolleg in Bielefeld. Oksana Melnyk hat die Fachlogik objektorientiert entworfen. Deine Aufgabe ist es, die Vermittlung zwischen Gesuchen und Angeboten zu programmieren. Folgende Klassen sind vorhanden:

Klassendiagramm der Fahrtenbörse mit den Klassen Fahrtenboerse, Angebot, Gesuch, Buchung, Haltepunkt, Nutzer, Zeitpunkt und Richtung (mit KI erstellt)
  • Für alle Attribute gibt es öffentliche Getter und Setter (z. B. getFreiePlaetze(), getBuchungen()).

  • Haltepunkt und Nutzer vergleichen zwei Objekte mit equals(…) inhaltlich; Werte der Aufzählung Richtung vergleichst Du direkt.

  • z1.istVor(z2) liefert true, wenn z1 echt vor z2 liegt; z1.gleicherTag(z2) liefert true, wenn beide Zeitpunkte auf denselben Kalendertag fallen. Zeitpunkt.jetzt() liefert den aktuellen Zeitpunkt.

Beispieldaten für Dienstag, den 20.10.2026 (Auszug aus der Liste angebote):

Angebote in der Fahrtenbörse (Beispiel)
Nr. Fahrer*in Haltepunkt Richtung Abfahrt freie Plätze
1 Ben Richter Gütersloh Hbf ZUR_SCHULE 20.10.2026 07:00 2
2 Ben Richter Gütersloh Hbf NACH_HAUSE 20.10.2026 14:20 3
3 Thomas Becker Gütersloh Hbf ZUR_SCHULE 20.10.2026 07:15 1
4 Marie Schulz Herford P&R ZUR_SCHULE 20.10.2026 06:50 3
5 Ben Richter Gütersloh Hbf ZUR_SCHULE 21.10.2026 07:00 2
6 Jonas Wolff Gütersloh Hbf ZUR_SCHULE 20.10.2026 07:25 0
7 Emma Lorenz Gütersloh Hbf ZUR_SCHULE 20.10.2026 06:55 3

Lukas Hofmann sucht eine Fahrt ab Gütersloh Hbf, Richtung ZUR_SCHULE, Abfahrt zwischen 20.10.2026 06:45 und 07:30 (beide Grenzen eingeschlossen). Für die Rückfahrt am 20.10. hat er bereits Angebot 2 angefragt.

a) Implementiere in der Klasse Fahrtenboerse die Methode passendeAngebote(g: Gesuch): List<Angebot>. Ein Angebot passt zum Gesuch g, wenn Haltepunkt und Richtung übereinstimmen, die Abfahrt im Zeitfenster liegt, mindestens ein Platz frei ist und die suchende Person nicht selbst fährt. Welche Angebote liefert die Methode für Lukas? (8 Punkte)

Funktion passendeAngebote(g: Gesuch): List<Angebot>
    ergebnis: List<Angebot> := new List<Angebot>()
    für jedes a in angebote
        imFenster: boolean := nicht a.getAbfahrt().istVor(g.getFruehestens()) und nicht g.getSpaetestens().istVor(a.getAbfahrt())
        gleicherWeg: boolean := a.getHaltepunkt().equals(g.getHaltepunkt()) und a.getRichtung() = g.getRichtung()
        wenn gleicherWeg und imFenster und a.getFreiePlaetze() > 0 und nicht a.getFahrer().equals(g.getErsteller()) dann
            ergebnis.add(a)
        Ende wenn
    Ende für
    Rückgabe ergebnis
Ende passendeAngebote

„Im Fenster“ heißt: nicht vor dem frühesten und nicht nach dem spätesten Zeitpunkt. Weil istVor echt vergleicht, gehören beide Grenzen dazu. Für Lukas liefert die Methode die Angebote 1, 3 und 7 (in dieser Reihenfolge). Angebot 2 hat die falsche Richtung, 4 einen anderen Haltepunkt, 5 einen anderen Tag, 6 keinen freien Platz.

Bewertung: Ergebnisliste anlegen und zurückgeben 1 Punkt, Schleife 1 Punkt, Haltepunkt mit equals 1 Punkt, Richtung 1 Punkt, Zeitfenster mit istVor einschließlich der Grenzen 2 Punkte, freie Plätze 1 Punkt, eigene Angebote ausschließen und Ergebnis der Beispieldaten 1 Punkt.

b) Die App soll die passenden Angebote nach Abfahrt geordnet anzeigen, die früheste zuerst. Entwickle die Methode nachAbfahrtSortiert(g: Gesuch): List<Angebot>. Sie nutzt a) und fügt jedes Angebot an der richtigen Stelle in eine neue Liste ein. Bei gleicher Abfahrt bleibt die Reihenfolge aus a) erhalten. Gib das Ergebnis für Lukas an. (6 Punkte)

Funktion nachAbfahrtSortiert(g: Gesuch): List<Angebot>
    sortiert: List<Angebot> := new List<Angebot>()
    für jedes a in passendeAngebote(g)
        pos: integer := 0
        solange pos < sortiert.size() und nicht a.getAbfahrt().istVor(sortiert.get(pos).getAbfahrt())
            pos := pos + 1
        Ende solange
        sortiert.add(pos, a)
    Ende für
    Rückgabe sortiert
Ende nachAbfahrtSortiert

Ergebnis für Lukas: 7 (06:55), 1 (07:00), 3 (07:15).

Die innere Schleife sucht die erste Position, deren Abfahrt später liegt als die des neuen Angebots. Weil bei Gleichstand weitergesucht wird, landet ein gleich frühes Angebot hinter dem vorhandenen; die Reihenfolge aus a) bleibt also erhalten (stabiles Sortieren durch Einfügen).

Bewertung: Methode aus a) nutzen 1 Punkt, neue Liste und Rückgabe 1 Punkt, Einfügeposition mit Abbruch am Listenende suchen 2 Punkte, Vergleich über istVor mit richtiger Behandlung gleicher Zeiten 1 Punkt, Einfügen mit add(pos, a) und Ergebnis 1 Punkt. Wer zuerst alles in eine Liste übernimmt und dann mit einem bekannten Sortierverfahren sortiert, erhält bei richtiger Umsetzung ebenfalls die volle Punktzahl.

c) Entwickle die Methode anfragen(a: Angebot, n: Nutzer): Boolean der Klasse Fahrtenboerse. Sie legt eine noch unbestätigte Buchung für n beim Angebot a an und liefert true. Sie liefert false und legt nichts an, wenn

  • kein Platz mehr frei ist oder n das Angebot selbst anbietet oder

  • n bereits eine Buchung bei irgendeinem Angebot derselben Richtung am selben Tag hat (auch beim Angebot a selbst).

Die Klasse Buchung erhält dafür den Konstruktor Buchung(mitfahrer: Nutzer, angefragtAm: Zeitpunkt), die Klasse Angebot die Methode buchungHinzufuegen(b: Buchung). Was liefern nacheinander anfragen(Angebot 1, Lukas), anfragen(Angebot 3, Lukas) und anfragen(Angebot 6, Lukas)? (8 Punkte)

Funktion anfragen(a: Angebot, n: Nutzer): boolean
    wenn a.getFreiePlaetze() = 0 oder a.getFahrer().equals(n) dann
        Rückgabe false
    Ende wenn
    konflikt: boolean := false
    für jedes x in angebote
        wenn x.getRichtung() = a.getRichtung() und x.getAbfahrt().gleicherTag(a.getAbfahrt()) dann
            für jedes b in x.getBuchungen()
                wenn b.getMitfahrer().equals(n) dann
                    konflikt := true
                Ende wenn
            Ende für
        Ende wenn
    Ende für
    wenn konflikt dann
        Rückgabe false
    Ende wenn
    a.buchungHinzufuegen(new Buchung(n, Zeitpunkt.jetzt()))
    Rückgabe true
Ende anfragen

Ergebnisse: Angebot 1 → true (Lukas’ vorhandene Buchung gilt der Rückfahrt). Angebot 3 → false (inzwischen hat er bei Angebot 1 eine Fahrt zur Schule am selben Tag). Angebot 6 → false (kein Platz frei).

Bewertung:

  • Platz und eigenes Angebot vorab prüfen: 1 Punkt

  • Schleife über alle Angebote mit Bedingung gleiche Richtung und gleicher Tag: 2 Punkte

  • innere Schleife über die Buchungen des Angebots (über den Getter) mit equals: 2 Punkte

  • Ergebnis der Suche in einer Variablen und erst nach den Schleifen ausgewertet: 1 Punkt

  • Buchung mit Konstruktor und Zeitpunkt.jetzt() über buchungHinzufuegen eingetragen: 1 Punkt (nicht direkt auf die private Liste zugreifen; die freien Plätze ändern sich erst bei der Bestätigung)

  • Ergebnisse der drei Aufrufe: 1 Punkt

d) Ergänze das Klassendiagramm um alle Methoden und Konstruktoren, die Du in a) bis c) implementiert oder vorausgesetzt hast, und lege die Beziehungsart zwischen Angebot und Buchung fest. Begründe die Beziehungsart kurz. Es genügen die Klassen Fahrtenboerse, Angebot und Buchung. (4 Punkte)

Ergänztes Klassendiagramm mit den drei neuen Methoden der Fahrtenbörse, buchungHinzufuegen im Angebot und dem Konstruktor der Buchung (mit KI erstellt)

Bewertung:

  • drei Methoden in Fahrtenboerse mit vollständiger Signatur: 1 Punkt

  • buchungHinzufuegen(b: Buchung) in Angebot: 1 Punkt

  • Konstruktor Buchung(mitfahrer: Nutzer, angefragtAm: Zeitpunkt) ohne Rückgabetyp: 1 Punkt

  • Komposition mit Begründung: Eine Buchung gehört zu genau einem Angebot, entsteht nur über dieses Angebot und ist ohne es sinnlos: 1 Punkt (eine Aggregation mit nachvollziehbarer Begründung ist ebenfalls richtig)

Aufgabe 3.2: Absatz nach Artikeln und Ofenprotokoll im Fahrradshop (Profilkompetenz)

(ca. 27 min Bearbeitungszeit)

Du bist Auszubildende*r im IT-Team der CSB-Rad GmbH in Bielefeld. Natalia Wróbel aus dem Controlling möchte wissen, welche Artikel sich in einem Zeitraum wie oft verkauft haben und an welchem Wochentag der Shop am meisten umsetzt. Außerdem liefert der Fertigungspartner Rahmenwerk OWL GmbH Messwerte aus seinem Einbrennofen, mit denen die Qualität der Pulverbeschichtung belegt werden soll. Folgende Klassen sind vorhanden:

Klassendiagramm mit den Klassen Verkauf und Ofenmesswert sowie den Datentypen Datum und Zeitpunkt (mit KI erstellt)
  • Für alle Attribute gibt es öffentliche Getter.

  • Datumswerte kannst Du mit <, <= und == vergleichen. d.getWochentag() liefert 1 für Montag bis 7 für Sonntag.

  • Eine Map<K, V> ordnet Schlüsseln Werte zu: put(k, v) legt einen Wert ab oder ersetzt ihn, get(k) liest ihn, containsKey(k) prüft, ob es den Schlüssel gibt; eine leere Map entsteht mit new HashMap<K, V>(). In Pseudo-Python ist die Map ein Dictionary (m = {}, m[k] = v, m[k], k in m).

Die Verkäufe liegen in der Liste verkaeufe vom Typ List<Verkauf> (Auszug, Preise netto):

Liste verkaeufe (Beispiel)
Index datum artikelNr menge einzelpreis
0 Mo 05.10.2026 KET-PFL-01 3 8,40
1 Mo 05.10.2026 LIC-SET-01 1 68,07
2 Di 06.10.2026 SCH-BUE-01 2 62,18
3 Mi 07.10.2026 KET-PFL-01 5 8,40
4 Fr 09.10.2026 RAD-CITY-01 1 671,43
5 Sa 10.10.2026 LIC-SET-01 4 68,07
6 Sa 10.10.2026 KET-PFL-01 2 8,40
7 Mo 12.10.2026 SCH-BUE-01 1 62,18

a) Entwickle die Methode mengeJeArtikel(verkaeufe: List<Verkauf>, start: Datum, ende: Datum): Map<String, Integer>. Sie liefert für jede Artikelnummer, die im Zeitraum von start bis ende (beide eingeschlossen) verkauft wurde, die verkaufte Gesamtmenge. Die Liste soll dabei nur einmal durchlaufen werden. Gib das Ergebnis für den 05.10. bis 10.10.2026 an. (7 Punkte)

Funktion mengeJeArtikel(verkaeufe: List<Verkauf>, start: Datum, ende: Datum): Map<string, integer>
    ergebnis: Map<string, integer> := new HashMap<string, integer>()
    für jedes v in verkaeufe
        wenn start <= v.getDatum() und v.getDatum() <= ende dann
            nr: string := v.getArtikelNr()
            wenn ergebnis.containsKey(nr) dann
                ergebnis.put(nr, ergebnis.get(nr) + v.getMenge())
            sonst
                ergebnis.put(nr, v.getMenge())
            Ende wenn
        Ende wenn
    Ende für
    Rückgabe ergebnis
Ende mengeJeArtikel

Ergebnis: KET-PFL-01 → 10, LIC-SET-01 → 5, SCH-BUE-01 → 2, RAD-CITY-01 → 1. Der Verkauf vom 12.10. liegt außerhalb.

Bewertung: leere Map anlegen und zurückgeben 1 Punkt, Schleife über alle Verkäufe 1 Punkt, Zeitraum mit beiden Grenzen 1 Punkt, Fallunterscheidung „Schlüssel vorhanden?“ 1 Punkt, vorhandene Menge erhöhen statt überschreiben 1 Punkt, neuen Schlüssel mit der Menge anlegen 1 Punkt, Ergebnis 1 Punkt.

Eine Map erspart den Zwischenschritt, erst alle Artikelnummern zu sammeln: Der Schlüssel wird beim ersten Treffer angelegt.

b) Cem Sarıkaya hatte vor Deiner Lösung einen Entwurf geschrieben. Die Zeilen sind durchnummeriert, die erste Zeile ist der Methodenkopf.

Funktion mengeJeArtikel(verkaeufe: List<Verkauf>, start: Datum, ende: Datum): Map<string, integer>
    ergebnis: Map<string, integer> := new HashMap<string, integer>()
    zähle i von 1 bis verkaeufe.size() - 1
        v: Verkauf := verkaeufe.get(i)
        wenn start < v.getDatum() und v.getDatum() <= ende dann
            wenn ergebnis.containsKey(v.getArtikelNr()) dann
                ergebnis.put(v.getArtikelNr(), v.getMenge())
            sonst
                ergebnis.put(v.getArtikelNr(), v.getMenge())
            Ende wenn
        Ende wenn
    Ende zähle
    Rückgabe ergebnis
Ende mengeJeArtikel

ba) Führe den Entwurf mit den Beispieldaten und dem Zeitraum 05.10. bis 10.10.2026 durch. Gib die Map an, die er liefert, und markiere die Abweichungen zum Ergebnis aus a). (3 Punkte)

i Verkauf im Zeitraum laut Zeile 5? Map danach
– Index 0 wird nicht gelesen – {}
1 05.10. LIC-SET-01, 1 nein (05.10. < 05.10. ist falsch) {}
2 06.10. SCH-BUE-01, 2 ja SCH 2
3 07.10. KET-PFL-01, 5 ja SCH 2, KET 5
4 09.10. RAD-CITY-01, 1 ja SCH 2, KET 5, RAD 1
5 10.10. LIC-SET-01, 4 ja …, LIC 4
6 10.10. KET-PFL-01, 2 ja, Wert ersetzt SCH 2, KET 2, RAD 1, LIC 4
7 12.10. nein unverändert

Abweichungen: KET-PFL-01 2 statt 10, LIC-SET-01 4 statt 5. Bewertung: Ablauf 2 Punkte, Abweichungen 1 Punkt.

bb) Nenne die drei Fehler des Entwurfs mit Zeilennummer und gib jeweils die korrigierte Zeile an. Erkläre, warum die Testdaten zwei dieser Fehler nicht auseinanderhalten können. (4 Punkte)

  • Zeile 3: Die Schleife beginnt bei 1, der erste Verkauf fehlt.

  • Zeile 5: start < schließt den ersten Tag aus; richtig ist start <=.

  • Zeile 7: Ist der Schlüssel schon vorhanden, wird die Menge ersetzt statt addiert.

Korrigierte Zeilen 3, 5 und 7:

    zähle i von 0 bis verkaeufe.size() - 1
        wenn start <= v.getDatum() und v.getDatum() <= ende dann
                ergebnis.put(v.getArtikelNr(), ergebnis.get(v.getArtikelNr()) + v.getMenge())

Der Verkauf mit Index 0 fällt am 05.10., also auf den ersten Tag. Er fehlt wegen Zeile 3 und wegen Zeile 5; das Ergebnis zeigt nicht, welcher Fehler die Ursache ist. Ein guter Testfall trennt die Fehler, z. B. ein Verkauf am ersten Tag an Position 1 und einer an einem mittleren Tag an Position 0.

Bewertung: je Fehler mit Korrektur 1 Punkt, Erklärung 1 Punkt.

c) Entwickle die Methode staerksterWochentag(verkaeufe: List<Verkauf>): Integer. Sie summiert den Umsatz (Menge mal Einzelpreis) aller Verkäufe getrennt nach Wochentag in einem Array mit sieben Einträgen und liefert die Nummer des Wochentags mit dem höchsten Umsatz (1 = Montag). Welchen Wochentag liefert sie für die Beispieldaten, und wie aussagekräftig ist das Ergebnis? (6 Punkte)

Funktion staerksterWochentag(verkaeufe: List<Verkauf>): integer
    umsatz: double[7] := [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    für jedes v in verkaeufe
        index: integer := v.getDatum().getWochentag() - 1
        umsatz[index] := umsatz[index] + v.getMenge() * v.getEinzelpreis()
    Ende für
    besterIndex: integer := 0
    zähle i von 1 bis 6
        wenn umsatz[i] > umsatz[besterIndex] dann
            besterIndex := i
        Ende wenn
    Ende zähle
    Rückgabe besterIndex + 1
Ende staerksterWochentag

Umsätze: Mo 155,45 €, Di 124,36 €, Mi 42,00 €, Do 0 €, Fr 671,43 €, Sa 289,08 €, So 0 €. Die Methode liefert 5 (Freitag).

Aussagekraft: Der Freitag liegt nur wegen eines einzigen Citybikes vorn; ohne diesen Verkauf wäre es der Samstag. Bei Daten aus gut einer Woche entscheidet ein Einzelverkauf über das Ergebnis; für eine Aussage braucht es mehrere Monate, und die Zahl der Verkäufe je Wochentag sollte mit betrachtet werden.

Bewertung: Array mit sieben Nullen 1 Punkt, Index aus dem Wochentag (minus 1) 1 Punkt, Umsatz aufsummieren 1 Punkt, Maximum mit Index suchen und als Wochentag (plus 1) zurückgeben 2 Punkte, Ergebnis mit Bewertung 1 Punkt.

d) Rahmenwerk OWL misst beim Einbrennen jede Minute die Objekttemperatur eines Rahmens. Die Messwerte liegen zeitlich geordnet im Array messwerte vom Typ Ofenmesswert[] vor. Laut Datenblatt des Pulvers muss die Temperatur an zwölf aufeinanderfolgenden Messungen mindestens 175 °C betragen.

Messwerte ab 10:00 Uhr (in °C): 165, 171, 176, 178, 177, 174, 176, 177, 179, 180, 181, 180, 179, 178, 177, 176, 175, 172, 168, 160

da) Entwickle die Methode beginnHaltephase(messwerte: Ofenmesswert[], mindest: Real, benoetigt: Integer): Zeitpunkt. Sie liefert den Zeitpunkt der ersten Messung der ersten Folge, in der benoetigt Messwerte hintereinander mindestens mindest erreichen, oder null, wenn es keine solche Folge gibt. Die Suche soll enden, sobald die Folge lang genug ist. (7 Punkte)

Funktion beginnHaltephase(messwerte: Ofenmesswert[], mindest: double, benoetigt: integer): Zeitpunkt
    folge: integer := 0
    i: integer := 0
    solange i < laenge(messwerte) und folge < benoetigt
        wenn messwerte[i].getTemperatur() >= mindest dann
            folge := folge + 1
        sonst
            folge := 0
        Ende wenn
        i := i + 1
    Ende solange
    wenn folge < benoetigt dann
        Rückgabe null
    Ende wenn
    Rückgabe messwerte[i - benoetigt].getZeit()
Ende beginnHaltephase

Endet die Schleife, weil die Folge lang genug ist, zeigt i auf den Messwert hinter der Folge. Die Folge beginnt deshalb bei i - benoetigt.

Bewertung: Zähler für die laufende Folge 1 Punkt, Schleife mit Index über das Array 1 Punkt, Abbruch, sobald benoetigt erreicht ist 1 Punkt, Zähler erhöhen bzw. zurücksetzen 2 Punkte, null ohne ausreichende Folge 1 Punkt, Startindex der Folge richtig berechnet 1 Punkt.

db) Was liefert beginnHaltephase für das Beispiel mit 175.0 und 12? Der Schichtleiter meint: „Elf von zwölf, das reicht.“ Nimm Stellung. (3 Punkte)

Die längste Folge reicht von 10:06 Uhr (176 °C) bis 10:16 Uhr (175 °C) und umfasst elf Messwerte; die erste Folge (10:02–10:04) hat drei. Die Methode liefert null (1 Punkt).

Stellungnahme (2 Punkte): Die Vorgabe des Pulverherstellers ist eine Mindestanforderung; darunter ist nicht sicher, dass die Beschichtung vollständig vernetzt und später haftet oder korrosionsbeständig ist. Der Rahmen gilt deshalb als nicht ordnungsgemäß eingebrannt und muss nach Herstellerangabe nachbehandelt oder gesperrt werden. Sinnvoll ist eine Warnung an den Ofen, sobald eine Haltephase zu kurz zu werden droht.

Aufgabe 3.3: Seitenweise Sessionliste und Technikrunde beim Barcamp (Profilkompetenz)

(ca. 29 min Bearbeitungszeit)

Du arbeitest im Orga-Team des Barcamps „Lernen.Digital.Leben 2027“ am Ratz und Rübe Berufskolleg mit. Die Barcamp-App zeigt alle eingereichten Sessions als Liste an und lädt sie dafür seitenweise vom Info-Server. Emre Aksoy, Leiter des Technikteams, braucht außerdem Hilfe bei der Überwachung der Anzeigegeräte und bei der Planung seiner Runden.

Für die Schnittstelle sind folgende Klassen vorhanden:

Klassendiagramm der Session-Schnittstelle mit SessionController, SessionService, Session, HttpAntwort und JsonWandler (mit KI erstellt)
  • service.alleSessions() liefert alle Sessions in der Reihenfolge, in der die App sie anzeigt.

  • JsonWandler.zuJson(liste) liefert die Sessions als JSON-Text, JsonWandler.fehler(text) einen JSON-Text mit einer Fehlermeldung.

Die App ruft sessionsAbrufen(seite, proSeite) auf. Es gilt:

  • Seite 1 enthält die ersten proSeite Sessions, Seite 2 die nächsten und so weiter; die letzte Seite darf weniger enthalten.

  • Ist seite kleiner als 1 oder proSeite nicht zwischen 1 und 20, antwortet der Server mit Status 400.

  • Gibt es die angefragte Seite nicht, antwortet er mit Status 404. Seite 1 gibt es immer, notfalls ohne Sessions.

  • Sonst antwortet er mit Status 200, den Sessions der Seite als JSON und der Kopfzeile X-Total-Count mit der Gesamtzahl der Sessions.

aa) Zurzeit sind 23 Sessions eingereicht. Entscheide für jede Anfrage, mit welchem Status der Server antwortet und, bei Status 200, welche Indizes der Gesamtliste die Seite enthält. (3 Punkte)

Anfragen an die Session-Schnittstelle
Anfrage seite proSeite
1 1 10
2 3 10
3 4 10
4 0 5
5 2 25
6 5 5
Anfrage Status Indizes
1 200 0 bis 9
2 200 20 bis 22 (nur 3 Sessions)
3 404 – (es gibt nur 3 Seiten)
4 400 –
5 400 –
6 200 20 bis 22 (5 Seiten, die letzte mit 3 Sessions)

Je zwei richtige Anfragen 1 Punkt.

ab) Implementiere die private Methode seiteHolen(alle: List<Session>, seite: Integer, proSeite: Integer): List<Session>. Du kannst davon ausgehen, dass die Parameter bereits geprüft sind und die Seite existiert. (5 Punkte)

Funktion seiteHolen(alle: List<Session>, seite: integer, proSeite: integer): List<Session>
    ergebnis: List<Session> := new List<Session>()
    erster: integer := (seite - 1) * proSeite
    grenze: integer := erster + proSeite
    wenn grenze > alle.size() dann
        grenze := alle.size()
    Ende wenn
    zähle i von erster bis grenze - 1
        ergebnis.add(alle.get(i))
    Ende zähle
    Rückgabe ergebnis
Ende seiteHolen

Bewertung: Ergebnisliste anlegen und zurückgeben 1 Punkt, ersten Index aus Seite und Seitenlänge berechnen 1 Punkt, Grenze berechnen und auf die Listenlänge begrenzen 2 Punkte, Schleife mit Übernahme der Sessions 1 Punkt.

ac) Implementiere die öffentliche Methode sessionsAbrufen(seite: Integer, proSeite: Integer): HttpAntwort nach den oben genannten Regeln. Nutze die Methode aus ab). (7 Punkte)

Funktion sessionsAbrufen(seite: integer, proSeite: integer): HttpAntwort
    wenn seite < 1 oder proSeite < 1 oder proSeite > 20 dann
        Rückgabe new HttpAntwort(400, JsonWandler.fehler("seite oder proSeite ungültig"))
    Ende wenn
    alle: List<Session> := service.alleSessions()
    seitenGesamt: integer := (alle.size() + proSeite - 1) div proSeite
    wenn seite > 1 und seite > seitenGesamt dann
        Rückgabe new HttpAntwort(404, JsonWandler.fehler("Seite " & seite & " gibt es nicht"))
    Ende wenn
    antwort: HttpAntwort := new HttpAntwort(200, JsonWandler.zuJson(seiteHolen(alle, seite, proSeite)))
    antwort.setHeader("X-Total-Count", "" & alle.size())
    Rückgabe antwort
Ende sessionsAbrufen

Die Zahl der Seiten ist eine aufgerundete Division. In Ganzzahlarithmetik gelingt sie mit (anzahl + proSeite - 1) div proSeite: 23 Sessions mit 10 je Seite ergeben \lfloor 32 / 10 \rfloor = 3 Seiten. Alternativ zählt man, ob (seite - 1) * proSeite kleiner als die Gesamtzahl ist.

Bewertung:

  • Parameter vor dem Datenzugriff prüfen, Status 400: 2 Punkte

  • Sessions über den Service holen: 1 Punkt

  • Seitenzahl richtig ermitteln und nicht vorhandene Seite mit 404 beantworten, Seite 1 ausgenommen: 2 Punkte

  • Erfolgsantwort mit Methode aus ab), zuJson und Kopfzeile: 2 Punkte

Für die Anzeigegeräte und die Raumplanung gibt es außerdem die Klasse Sessionplaner:

Klassendiagramm des Sessionplaners mit der abstrakten Klasse Anzeige und ihren Unterklassen Tuerschild und Infomonitor (mit KI erstellt)
  • Anzeige.statusText() liefert die Raumnummer und „: keine Verbindung“, z. B. „Foyer: keine Verbindung“.

  • Tuerschild überschreibt statusText() und liefert die Raumnummer mit dem zuletzt gemeldeten Akkustand, z. B. „B.202: Akku 85 %“. Infomonitor überschreibt statusText() nicht.

ba) Am Morgen des Barcamps läuft im Sessionplaner der folgende Code; die Liste meldungen ist zu Beginn leer.

für jedes a in anzeigen
    wenn nicht a.istErreichbar() dann
        meldungen.add(a.statusText())
    Ende wenn
Ende für

Die Liste anzeigen enthält diese Objekte:

Anzeigegeräte am Morgen
Position Klasse raumNr akku istErreichbar()
0 Tuerschild A.104 12 false
1 Infomonitor Foyer – false
2 Tuerschild B.202 85 true
3 Infomonitor Mensa – true
4 Tuerschild C.110 4 false

Gib den Inhalt von meldungen nach dem Durchlauf an und begründe den zweiten Eintrag. (3 Punkte)

meldungen enthält „A.104: Akku 12 %“, „Foyer: keine Verbindung“ und „C.110: Akku 4 %“ (2 Punkte).

Der Infomonitor im Foyer überschreibt statusText() nicht. Zur Laufzeit wird für das Objekt die Methode seiner Klasse gesucht; weil Infomonitor keine eigene hat, wird die geerbte aus Anzeige ausgeführt. Für die Türschilder wird dagegen deren überschriebene Fassung aufgerufen, obwohl die Variable a den Typ Anzeige hat (1 Punkt).

bb) Ein Teammitglied schlägt vor, in der Schleife zu fragen, ob a ein Türschild ist, und den Text für Türschilder dort selbst zusammenzusetzen. Bewerte den Vorschlag. (2 Punkte)

Der Vorschlag funktioniert, ist aber schlechter: Die Schleife müsste jede Geräteart kennen und bei jeder neuen Art (etwa einem Beamer mit Lampenstunden) geändert werden; außerdem gelangt Wissen über den Aufbau des Türschilds in den Sessionplaner (1 Punkt). Mit der überschriebenen Methode entscheidet jedes Objekt selbst, welcher Text passt; neue Unterklassen funktionieren ohne Änderung der Schleife (1 Punkt).

c) Am Vorabend tauscht Emre die Akkus von vier E-Ink-Türschildern. Er startet im Orga-Büro A.010, geht immer zum nächstgelegenen noch nicht besuchten Türschild und kehrt am Ende ins Orga-Büro zurück (Nächster-Nachbar-Verfahren mit Rückkehr). Die Weglängen in Metern:

Weglängen zwischen den Standorten (symmetrisch)
von \ nach A.104 B.012 B.202 C.020
A.010 (Orga-Büro) 40 55 95 70
A.104 – 60 65 110
B.012 60 – 45 50
B.202 65 45 – 80

ca) Ermittle Emres Runde und ihre Gesamtlänge einschließlich des Rückwegs. (3 Punkte)

Schritt Standort Entfernungen zu den offenen Zielen gewählt
1 A.010 A.104: 40, B.012: 55, B.202: 95, C.020: 70 A.104 (40 m)
2 A.104 B.012: 60, B.202: 65, C.020: 110 B.012 (60 m)
3 B.012 B.202: 45, C.020: 50 B.202 (45 m)
4 B.202 C.020: 80 C.020 (80 m)
5 C.020 zurück zu A.010 70 m

Runde A.010 → A.104 → B.012 → B.202 → C.020 → A.010 mit 295 m. Ablauf 2 Punkte, Länge 1 Punkt.

cb) Finde eine kürzere Runde und erkläre, warum das Verfahren sie nicht gefunden hat. (3 Punkte)

A.010 → A.104 → B.202 → B.012 → C.020 → A.010 mit 40 + 65 + 45 + 50 + 70 = 270 m (oder dieselbe Runde rückwärts) (2 Punkte).

Das Verfahren entscheidet in jedem Schritt nur nach dem kürzesten nächsten Weg (gierig, greedy). Von A.104 aus wählt es B.012, weil 60 m kürzer sind als 65 m, und muss dann später den langen Weg B.202 → C.020 (80 m) gehen. Den Rückweg berücksichtigt es bei keiner Entscheidung (1 Punkt).

cc) Wie viele verschiedene Runden müsste ein Programm bei 30 Türschildern prüfen, um sicher die kürzeste zu finden? Warum ist das Nächster-Nachbar-Verfahren trotzdem sinnvoll? (2 Punkte)

Bei festem Start gibt es 30! Reihenfolgen; weil jede Runde vorwärts und rückwärts gleich lang ist, sind es \frac{30!}{2} \approx 1{,}3 \cdot 10^{32} verschiedene Runden – nicht in vertretbarer Zeit prüfbar (1 Punkt). Das Nächster-Nachbar-Verfahren braucht nur etwa 30 \cdot 30 Vergleiche und liefert meist eine brauchbare, wenn auch nicht immer die kürzeste Runde (1 Punkt).

d) Im Sessionplaner enthält das Array raumNr die acht Räume (A.001, A.104, A.105, B.012, B.201, B.202, C.110, C.020). Das zweidimensionale Array belegung hat für jeden Raum eine Zeile (gleicher Index wie in raumNr) und für jeden der fünf Slots eine Spalte; ein Eintrag ist die Session oder null, wenn der Raum frei ist.

Entwickle die Methode freieRaeume(slot: Integer): List<String>, die die Raumnummern aller Räume liefert, die im angegebenen Slot frei sind. Was liefert freieRaeume(2), wenn im dritten Slot A.001, A.104, B.202 und C.110 belegt sind? (4 Punkte)

Funktion freieRaeume(slot: integer): List<string>
    frei: List<string> := new List<string>()
    zähle r von 0 bis laenge(raumNr) - 1
        wenn belegung[r][slot] = null dann
            frei.add(raumNr[r])
        Ende wenn
    Ende zähle
    Rückgabe frei
Ende freieRaeume

freieRaeume(2) liefert A.105, B.012, B.201 und C.020 (der dritte Slot hat den Index 2).

Bewertung: Ergebnisliste anlegen und zurückgeben 1 Punkt, Schleife über alle Räume (erste Dimension) 1 Punkt, Zugriff mit Raum- und Slotindex und Vergleich mit null 1 Punkt, Raumnummer aus dem parallelen Array übernehmen und Ergebnis 1 Punkt.


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übungsaufgaben zu objektorientierten Algorithmen: Methoden über Objektlisten” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/algorithmen-objektorientiert-uebungsaufgaben veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/programmierung/programmiergrundlagen. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 28.10.2026.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: