Praxisprojekt
In dieser Lerneinheit untersuchst du anhand eines realen Beispiels aus der Logistik, wie du systematisch einen Algorithmus zur optimalen Routenplanung entwickelst. Du lernst die praktische Anwendung der Algorithmenentwicklung von der Problemanalyse bis zur fertigen Lösung kennen und siehst, wie theoretische Konzepte in der Praxis eingesetzt werden. Durch das konkrete Beispiel verstehst du die einzelnen Entwicklungsschritte und typische Herausforderungen bei der Umsetzung komplexer Algorithmen.
Einführung
Stell dir vor, du arbeitest in der IT-Abteilung einer Universität. Die Dekanin möchte endlich wissen, in welchen Fächern besonders viele Studierende durchfallen – um gezielt die Lehre zu verbessern.

Deine Aufgabe: Entwickle ein kleines Programm, das diese Durchfaller automatisch zählt und übersichtlich darstellt.
Mit diesem Praxisprojekt tauchst du direkt in ein realistisches Anwendungsszenario ein, bei dem Programmierlogik und Datenanalyse zusammenkommen.
Lernziele
Nach dieser Lerneinheit kannst du
- das Problem und die Datenstruktur erklären: Du verstehst, wie die Klasse
Pruefungaufgebaut ist und was unter „durchgefallen“ (note > 4.0) verstanden wird. - eine geeignete Strategie entwickeln: Du kannst begründen, warum ein Zähler-Array (Histogramm) und ein Single-Pass-Ansatz die effizienteste Lösung darstellen.
- den Algorithmus korrekt implementieren: Du setzt die Funktion
ermittle_durchfall_statistikselbstständig um – inklusive Schleife, Bedingung und Zählmechanismus pro Fach. - die Lösung prüfen und reflektieren: Du testest den Algorithmus mit Beispieldaten, interpretierst die Ergebnisse und bewertest Effizienz und Erweiterbarkeit.
Die Projektvorstellung
Das Problem: Die Dekanin einer Universität möchte schnell erkennen, in welchen Fächern es besonders viele “Durchfaller” gibt. Diese Statistik soll helfen zu entscheiden, wo eventuell die Lehre unterstützt werden muss.
Deine Datenbasis:
Du bekommst eine lange, unsortierte Liste (ergebnisse). Jeder Eintrag in dieser Liste ist ein Objekt der Klasse Pruefung.
Diese Klasse ist ganz einfach aufgebaut:
Klasse Pruefung
- fachNr : Integer // Nummer des Fachs (z.B. 0=Mathe, 1=Info, 2=BWL, ...)
- studentID : Integer // ID des Studenten
- note : Double // Erreichte Note (z.B. 1.0, 2.7, 5.0)(Für jedes Attribut gibt es eine Get-Methode, z.B. getFachNr()).
Deine konkrete Zielsetzung (Die Funktion)
Du sollst eine Funktion ermittle_durchfall_statistik schreiben. (Pseudocode)
- Input: Ein Array
ergebnisse[], voll mitPruefung-Objekten. - Definition “Durchgefallen”: Ein Student gilt als durchgefallen, wenn die
noteschlechter als 4.0 ist (also z.B. 4.3, 4.7 oder 5.0). Eine 4.0 ist noch bestanden. - Output: Ein Integer-Array. An
Index 0soll stehen, wie viele Studenten in Fach 0 (Mathe) durchgefallen sind. AnIndex 1, wie viele in Fach 1 (Info), usw.
Die Strategie
Die wichtigste Frage ist: Wie zählst du die Durchfaller pro Fach?
Das Kernkonzept: Das Zähler-Array
Du brauchst einen “Behälter”, um deine Zählerstände zu speichern. Die eleganteste Lösung ist ein Zähler-Array (auch Histogramm genannt).
Stell es dir vor wie eine Reihe von Punktezählern oder digitalen Strichlisten an der Wand – eine für jedes Fach:
- Fach 0 (Mathe):
[ 0 ] - Fach 1 (Info):
[ 0 ] - Fach 2 (BWL):
[ 0 ]
Wenn du 10 Fächer (0-9) hast, erstellst du einfach ein Array der Größe 10:
zaehler = new Integer[10]
Am Anfang ist dieses Array voller Nullen: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Der “Single-Pass”-Ansatz
Du musst nichts sortieren. Du kannst die ganze Liste (ergebnisse) von oben nach unten in einem einzigen Durchlauf (“Single Pass”) abarbeiten.
- Erstelle dein leeres
zaehler-Array (voller Nullen). - Starte eine Schleife, die jeden einzelnen Eintrag im
ergebnisse-Array anschaut. - Pro Eintrag stellst du zwei Fragen:
- Ist die
note> 4.0? - Wenn ja: Welches
fachNrhat dieser Eintrag?
- Ist die
- Nimm diese
fachNrund erhöhe den Zähler an genau dieser Stelle. (z.B.zaehler[fachNr]++) - Wenn die Schleife fertig ist, gibst du das
zaehler-Array zurück.
”Muss ich die Daten nicht erst nach Fach sortieren?”
Nein! Das ist das Gute an diesem Ansatz. Der Trick ist, dass du die fachNr direkt als Index (also als “Adresse” oder “Position”) für dein Zähler-Array benutzt.
- Es ist egal, ob ein Durchfaller in “Mathe” (Fach 0) als Erster oder als Letzter in deiner Liste auftaucht. In beiden Fällen machst du am Ende
zaehler[0]++. Das Ergebnis im Zähler-Array ist am Ende dasselbe.
Schritt-für-Schritt zur Lösung (Die Umsetzung)
Machen wir das Ganze jetzt konkret. Du bekommst folgende ergebnisse (7 Einträge).
Dein Mini-Datenbeispiel:
Index i | getFachNr() | getNote() | (StudentID ist egal) |
|---|---|---|---|
| 0 | 1 (Info) | 2.0 | … |
| 1 | 2 (BWL) | 5.0 | … |
| 2 | 1 (Info) | 1.3 | … |
| 3 | 1 (Info) | 5.0 | … |
| 4 | 0 (Mathe) | 3.0 | … |
| 5 | 2 (BWL) | 1.0 | … |
| 6 | 1 (Info) | 4.0 | … |
Schritt 0: Das Grundgerüst (Das Setup)
Du legst deine Funktion und dein leeres Zähler-Array an (wir nehmen für das Beispiel an, es gibt nur 3 Fächer: 0, 1, 2):
funktion ermittle_durchfall_statistik(ergebnisse[] : Pruefung) : Integer[]
// Annahme: Es gibt 3 Fächer (0, 1, 2)
durchfall_zaehler = new Integer[3]
// Dein Array sieht jetzt so aus:
// Index: [0] [1] [2]
// Wert: [0, 0, 0]
// ... hier kommt deine Schleife ...
Rückgabe durchfall_zaehler
ende funktionDieser Code definiert das “Gerüst” deiner Funktion. Sie nimmt das ergebnisse-Array als Input und verspricht, ein Integer-Array (Integer[]) als Output zurückzugeben. Die wichtigste Zeile ist durchfall_zaehler = new Integer[3]: Hier erstellst du dein Zähler-Array (deine “Strichliste”) mit drei Plätzen (für Fach 0, 1 und 2), die alle automatisch mit 0 starten.
Schritt 1: Die Schleife (Die Abarbeitung)
Jetzt gehst du die 7 Einträge des Mini-Beispiels durch. Der folgende Code kommt in den leeren Bereich von oben.
// 2. Verarbeite jeden Eintrag in der Liste
für (i = 0; i < ergebnisse.length; i++)
eintrag = ergebnisse[i]
// 3. Prüfe die Bedingung
wenn eintrag.getNote() > 4.0
// 4. Finde die richtige Position (Index)
fach = eintrag.getFachNr()
// 5. Erhöhe den Zähler an dieser Position
durchfall_zaehler[fach]++
ende wenn
ende fürDie für-Schleife. Sie läuft die ergebnisse-Liste von oben (i = 0) bis zum Ende (ergebnisse.length) durch. In jedem Durchlauf prüft die wenn-Bedingung, ob die Note schlechter als 4.0 ist (also “durchgefallen”). Nur wenn das zutrifft, holt sich der Code die fachNr und benutzt diese Nummer als Index, um den Zähler an der exakt richtigen Stelle (durchfall_zaehler[fach]++) um eins zu erhöhen.
Verfolgung der Schleife (Was genau passiert)
Schau dir genau an, wie sich dein durchfall_zaehler-Array bei jedem Schritt verändert:
für (i = 0; i < ergebnisse.length; i++)
eintrag = ergebnisse[i]
wenn eintrag.getNote() > 4.0
fach = eintrag.getFachNr()
durchfall_zaehler[fach]++
ende wenn
ende füri | Eintrag (Note, Fach) | Bedingung (note > 4.0)? | Aktion | durchfall_zaehler (nach dem Schritt) |
|---|---|---|---|---|
| Start | - | - | - | [0, 0, 0] |
| 0 | (2.0, Fach 1) | Nein (2.0 ist nicht > 4.0) | Nichts. | [0, 0, 0] |
| 1 | (5.0, Fach 2) | Ja! (5.0 ist > 4.0) 🚩 | fach = 2. Erhöhe zaehler[2]. | [0, 0, 1] |
| 2 | (1.3, Fach 1) | Nein (1.3 ist nicht > 4.0) | Nichts. | [0, 0, 1] |
| 3 | (5.0, Fach 1) | Ja! (5.0 ist > 4.0) 🚩 | fach = 1. Erhöhe zaehler[1]. | [0, 1, 1] |
| 4 | (3.0, Fach 0) | Nein (3.0 ist nicht > 4.0) | Nichts. | [0, 1, 1] |
| 5 | (1.0, Fach 2) | Nein (1.0 ist nicht > 4.0) | Nichts. | [0, 1, 1] |
| 6 | (4.0, Fach 1) | Nein (4.0 ist nicht > 4.0) | Nichts. | [0, 1, 1] |
| Ende | - | - | - | [0, 1, 1] |
Finale Lösung
Die Schleife ist fertig. Deine Funktion geht nun zum letzten Schritt:
Rückgabe durchfall_zaehler
Das zurückgegebene Array ist [0, 1, 1].
Was bedeutet das? Du kannst der Dekanin jetzt berichten:
- Fach 0 (Mathe): 0 Durchfaller (Index 0 im Array)
- Fach 1 (Info): 1 Durchfaller (Index 1 im Array)
- Fach 2 (BWL): 1 Durchfaller (Index 2 im Array)
Du hast die Aufgabe mit einem einfachen, robusten und sehr schnellen “Single-Pass”-Algorithmus gelöst.
Der vollständige Pseudocode
Hier ist der finale Algorithmus, etwas allgemeiner für 10 Fächer (0-9):
funktion ermittle_durchfall_statistik(ergebnisse[] : Pruefung) : Integer[]
// Annahme: Es gibt 10 Fächer mit Nummern von 0 bis 9
anzahl_faecher = 10
// 1. Erstelle das Zähler-Array
durchfall_zaehler = new Integer[anzahl_faecher]
// (In vielen Sprachen ist es automatisch mit Nullen gefüllt)
// 2. Verarbeite jeden Eintrag in der Liste
für (i = 0; i < ergebnisse.length; i++)
eintrag = ergebnisse[i]
// 3. Prüfe die Bedingung
wenn eintrag.getNote() > 4.0
// 4. Finde die richtige Position (Index)
fach = eintrag.getFachNr()
// 5. Erhöhe den Zähler an dieser Position
durchfall_zaehler[fach]++
ende wenn
ende für
// 6. Gib das fertige Zähler-Array zurück
Rückgabe durchfall_zaehler
ende funktion
Was dieser Code macht: Diese Funktion erstellt ein leeres Zähler-Array (einen Zähler pro Fach). Sie durchläuft dann die gesamte Prüfungsliste (ergebnisse) Eintrag für Eintrag. Wenn sie eine Note findet, die “durchgefallen” (> 4.0) ist, erhöht sie den Zähler für das entsprechende Fach (fachNr). Am Ende gibt sie das fertige Zähler-Array zurück, das die Anzahl der Durchfaller pro Fach enthält.
Zusammenfassung
Zusammenfassung:
1. Die Aufgabe
Das Ziel war es, eine Funktion zu entwickeln, die eine unsortierte Liste von Prüfungsergebnissen verarbeitet. Für jedes Fach (identifiziert durch eine fachNr von 0, 1, 2, …) sollte gezählt werden, wie viele Studenten die Prüfung nicht bestanden haben (definiert als note > 4.0).
2. Das Kernkonzept (Das Zähler-Array)
Die zentrale Lösungsstrategie war die Verwendung eines Zähler-Arrays (auch Histogramm genannt).
- Dies ist ein Array, bei dem jeder Index (Position) direkt einem Fach entspricht (z.B. Index 0 = Fach 0, Index 1 = Fach 1).
- Der Wert an dieser Position ist der Zähler für die Durchfaller in diesem Fach.
- Beispiel: Ein Array
[1, 0, 1]bedeutet: 1 Durchfaller in Fach 0, 0 in Fach 1 und 1 in Fach 2.
3. Der Algorithmus (Der “Single-Pass”)
Der Algorithmus löst das Problem in einem einzigen Durchlauf (for-Schleife) durch die Daten, ohne dass sie vorher sortiert werden müssen:
- Initialisieren: Erstelle ein Zähler-Array (z.B.
durchfall_zaehler = new Integer[10]), das am Anfang überall mit Nullen gefüllt ist. - Durchlaufen: Gehe die Prüfungsliste (
ergebnisse) von Eintrag zu Eintrag durch. - Prüfen: Prüfe bei jedem Eintrag, ob die Bedingung
note > 4.0zutrifft. - Zählen: Wenn die Bedingung zutrifft:
- Lies die
fachNrdes Eintrags aus. - Erhöhe den Zähler an der entsprechenden Position im Zähler-Array (z.B.
durchfall_zaehler[fachNr]++).
- Lies die
- Rückgabe: Gib das fertige Zähler-Array zurück, wenn die Schleife alle Einträge verarbeitet hat.
4. Finaler Pseudocode:
Hier ist der finale Algorithmus, etwas allgemeiner für 10 Fächer (0-9):
funktion ermittle_durchfall_statistik(ergebnisse[] : Pruefung) : Integer[]
// Annahme: Es gibt 10 Fächer mit Nummern von 0 bis 9
anzahl_faecher = 10
// 1. Erstelle das Zähler-Array
durchfall_zaehler = new Integer[anzahl_faecher]
// (In vielen Sprachen ist es automatisch mit Nullen gefüllt)
// 2. Verarbeite jeden Eintrag in der Liste
für (i = 0; i < ergebnisse.length; i++)
eintrag = ergebnisse[i]
// 3. Prüfe die Bedingung
wenn eintrag.getNote() > 4.0
// 4. Finde die richtige Position (Index)
fach = eintrag.getFachNr()
// 5. Erhöhe den Zähler an dieser Position
durchfall_zaehler[fach]++
ende wenn
ende für
// 6. Gib das fertige Zähler-Array zurück
Rückgabe durchfall_zaehler
ende funktion
Was dieser Code macht: Diese Funktion erstellt ein leeres Zähler-Array (einen Zähler pro Fach). Sie durchläuft dann die gesamte Prüfungsliste (ergebnisse) Eintrag für Eintrag. Wenn sie eine Note findet, die “durchgefallen” (> 4.0) ist, erhöht sie den Zähler für das entsprechende Fach (fachNr). Am Ende gibt sie das fertige Zähler-Array zurück, das die Anzahl der Durchfaller pro Fach enthält.