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 Pruefung aufgebaut 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_statistik selbststä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 mit Pruefung-Objekten.
  • Definition “Durchgefallen”: Ein Student gilt als durchgefallen, wenn die note schlechter 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 0 soll stehen, wie viele Studenten in Fach 0 (Mathe) durchgefallen sind. An Index 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.

  1. Erstelle dein leeres zaehler-Array (voller Nullen).
  2. Starte eine Schleife, die jeden einzelnen Eintrag im ergebnisse-Array anschaut.
  3. Pro Eintrag stellst du zwei Fragen:
    1. Ist die note > 4.0?
    2. Wenn ja: Welches fachNr hat dieser Eintrag?
  4. Nimm diese fachNr und erhöhe den Zähler an genau dieser Stelle. (z.B. zaehler[fachNr]++)
  5. 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.
⏳ Lädt Dataview-Inhalt...

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 igetFachNr()getNote()(StudentID ist egal)
01 (Info)2.0
12 (BWL)5.0
21 (Info)1.3
31 (Info)5.0
40 (Mathe)3.0
52 (BWL)1.0
61 (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 funktion

Dieser 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ür

Die 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ür
iEintrag (Note, Fach)Bedingung (note > 4.0)?Aktiondurchfall_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.

⏳ Lädt Dataview-Inhalt...

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:

  1. Initialisieren: Erstelle ein Zähler-Array (z.B. durchfall_zaehler = new Integer[10]), das am Anfang überall mit Nullen gefüllt ist.
  2. Durchlaufen: Gehe die Prüfungsliste (ergebnisse) von Eintrag zu Eintrag durch.
  3. Prüfen: Prüfe bei jedem Eintrag, ob die Bedingung note > 4.0 zutrifft.
  4. Zählen: Wenn die Bedingung zutrifft:
    • Lies die fachNr des Eintrags aus.
    • Erhöhe den Zähler an der entsprechenden Position im Zähler-Array (z.B. durchfall_zaehler[fachNr]++).
  5. 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.