EuraStudy
Notizen/Informatik/INF-Alg - Algorithmen, Programmierung und Komplexität
Notizen · InformatikAT · Matura

INF-Alg - Algorithmen, Programmierung und Komplexität

Algorithmen sind endliche, eindeutige Handlungsvorschriften. Prüfungsrelevant sind Kontrollstrukturen, Rekursion, klassische Sortier- und Suchverfahren sowie die Beschreibung von Laufzeiten mit Big-O.

6 Abschnitte·~20 Min Lesezeit·4 Kompetenzen·Niveau Basis 2 · Standard 2 · Vertiefung 2·Stand 06/2026

T·0222 / 12
Prüfungsprofil
INF-Alg-1 · Kontrollstrukturen, Funktionen und Modularisierung verstehenINF-Alg-2 · Iterative und rekursive Algorithmen entwerfenINF-Alg-3 · Sortier- und Suchverfahren analysierenINF-Alg-4 · Laufzeit- und Speicherkomplexität mit Big-O beschreiben
Tiefe

Lesetiefe: Vertiefung

Schrift

Schriftgröße: Standard

Inhalt · 6 Abschnitte▾
  1. INF-Alg - Algorithmen, Programmierung und Komplexität
    • 01Kontrollstrukturen, Funktionen und Modularisierung○
    • 02Rekursion und Iteration◐
    • 03Sortierverfahren - Bubble, Insertion, Merge, Quicksort◐
    • 04Suchverfahren - linear und binaer○
    • 05Big-O, Master-Theorem und Grenzen●
    • 06Greedy- und Dynamic-Programming-Verfahren●
§ 01

Kontrollstrukturen, Funktionen und Modularisierung#

●○○BasisLPINF-Alg-1.1LPINF-Alg-1.2

Kernpunkte

Jeder Algorithmus, so komplex er auch sei, ist aus einem winzigen Wortschatz gebaut. Das Theorem von Böhm/Jacopini (1966) beweist, dass drei Kontrollstrukturen für jede berechenbare Funktion genügen: Sequenz (Anweisungen nacheinander), Selektion (if/else - eine Verzweigung anhand einer Bedingung wählen) und Iteration (while/for - wiederholen, solange eine Bedingung gilt). Ein GOTO ist nie nötig, und jedes Programm lässt sich als verschachtelte Kombination dieser drei lesen.
Eine Funktion bündelt ein Stück Verhalten hinter einem Namen, nimmt Parameter als Eingabe und liefert einen Rückgabewert. Das bringt drei Vorteile: Wiederverwendung (einmal schreiben, oft aufrufen), Abstraktion (der Aufrufer muss die Interna nicht kennen) und Testbarkeit (eine Funktion mit klarer Ein-/Ausgabe lässt sich isoliert prüfen). Der Vertrag lautet: gleiche Eingabe, gleiche Ausgabe.
Modularisierung führt das weiter und zerlegt ein Programm in unabhängige Bausteine mit je einer klaren Aufgabe (). Das senkt die kognitive Last, ermöglicht arbeitsteilige Entwicklung und lokalisiert Änderungen - eine Korrektur in einem Modul bricht selten ein anderes. Eine typische Zerlegung trennt etwa `einlesen()`, `berechnen()` und `ausgeben()` als eigene Funktionen unter einem schlanken Hauptprogramm.

Modularisierung - Aufrufgraph

ModularisierungNetzgraph, Hauptprogramm → einlesen(), Hauptprogramm → berechnen(), Hauptprogramm → ausgeben(), berechnen() → hilfsfunktion()Hauptprogrammeinlesen()berechnen()ausgeben()hilfsfunktion()
Abb. 1Ein kleines Hauptprogramm ruft spezialisierte Funktionen auf; jede Funktion hat genau eine Aufgabe.
Variablen haben eine Sichtbarkeit (Scope): Eine lokale Variable lebt nur innerhalb ihrer Funktion und verschwindet beim Rücksprung; eine globale Variable ist überall sichtbar, koppelt Module aber unsichtbar aneinander und ist eine häufige Fehlerquelle. Daten besser über Parameter übergeben, als auf Globale zuzugreifen.
Ein Seiteneffekt ist jede Wirkung über den Rückgabewert hinaus (eine globale Variable ändern, Datei- oder Bildschirm-I/O). Reine Funktionen - ohne Seiteneffekte, Ausgabe hängt nur von der Eingabe ab - sind deutlich leichter zu testen, zu parallelisieren und zu verstehen. Vorhandene Seiteneffekte einer Funktion sollten dokumentiert sein.
Codeausschnitt Python: ```python def bmi(masse_kg, größe_m): return masse_kg / (größe_m ** 2) for person in personen: print(person["name"], bmi(person["masse"], person["größe"])) ```
Musterbeispiel

Pseudocode -> Python

Übersetze den Pseudocode in Python: "Solange n > 1 wiederhole: wenn n gerade, n := n/2; sonst n := 3n+1. Zähle Schritte."

  1. 01Funktionssignatur

    `def collatz_schritte(n: int) -> int:`

  2. 02Schleife & Verzweigung

    ```python schritte = 0 while n > 1: n = n // 2 if n % 2 == 0 else 3 * n + 1 schritte += 1 return schritte ```

  3. 03Testfall

    `collatz_schritte(6)` ergibt 8 (6,3,10,5,16,8,4,2,1).

Ergebnis: Die Funktion liefert die Länge der Collatz-Folge ab Startwert nnn. Sie terminiert empirisch für alle bisher getesteten Werte - mathematisch unbewiesen!

Schritt-für-Schritt Erklärung3 Schritte
  1. 1

    Jedes Programm lässt sich aus Sequenz, Selektion und Iteration aufbauen - das ist das Theorem von Böhm/Jacopini.

  2. 2

    Funktionen sind die wichtigste Abstraktionsstufe: gleiche Eingabe ergibt gleiche Ausgabe, ohne Seiteneffekte ist Testen einfach.

  3. 3

    Modularisiere frühzeitig, damit jede Funktion einen einzigen klaren Zweck erfüllt.

SRDP-Aufgaben

SelbsttestAus der Fragenbank7 Punkte

Aufgabenstellung

Erkläre am Beispiel einer selbst gewählten Aufgabe die Bedeutung der drei elementaren Kontrollstrukturen Sequenz, Selektion und Iteration. Schreibe die Lösung in Pseudocode oder einer Programmiersprache deiner Wahl.

Maturafokus

  • Aufgabentyp: Pseudocode in eine konkrete Sprache (Python/JavaScript) übersetzen.
  • Auf saubere Trennung zwischen Eingabe (Parameter), Verarbeitung (Body) und Ausgabe (return) achten.
  • Bei mündlichen Prüfungen oft: zu einer Funktion das passende Aufrufbeispiel skizzieren.

Typische Fehler

  • return innerhalb einer Schleife vergessen oder zu früh gesetzt.
  • Globale Variable wird in einer Funktion überschrieben, statt Parameter zu verwenden.
  • Pseudocode vermischt sprachspezifische Details (z.B. Semikolons aus C, Einrückungen aus Python).

Aktive Wiederholung

Schreibe eine Python-Funktion `vokale_zählen(text)`, die die Anzahl der Vokale (a, e, i, o, u; gross/klein) zurückliefert. Demonstriere den Aufruf mit "Informatik".

Aktiv abrufen

Erinnere dich an die Kernpunkte — dann aufdecken.

Quellen: Böhm/Jacopini: Flow diagrams, Turing machines and languages with only two formation rules (CACM) · Python Software Foundation - Tutorial (PSF)

§ 02

Rekursion und Iteration#

●●○StandardLPINF-Alg-2.1

Kernpunkte

Rekursion löst ein Problem, indem es auf eine kleinere Instanz desselben Problems zurückgeführt wird: Eine rekursive Funktion ruft sich selbst mit „kleineren" Argumenten auf. Das ist oft die natürlichste Beschreibung selbstähnlicher Strukturen - Bäume, Listen, Divide-and-Conquer - und entspricht mathematisch einer Rekurrenz wie n!=n⋅(n−1)!n! = n\cdot(n-1)!n!=n⋅(n−1)!.
Jede Rekursion braucht zwei Teile: einen Basisfall, der ohne weiteren Selbstaufruf terminiert (0!=10! = 10!=1), und einen Rekursionsfall, der das Problem verkleinert und sich selbst aufruft (n!=n⋅(n−1)!n! = n\cdot(n-1)!n!=n⋅(n−1)!). Fehlt der Basisfall - oder verkleinert der Rekursionsfall das Argument nicht -, läuft die Funktion endlos, bis der Speicher voll ist.
Der Mechanismus dahinter ist der Aufruf-Stack (Call-Stack): Bei jedem Aufruf legt das Laufzeitsystem einen Stack-Frame mit Parametern, lokalen Variablen und Rückkehradresse ab; ist der Basisfall erreicht, werden die Frames in umgekehrter Reihenfolge abgebaut. Die maximale Rekursionstiefe bestimmt damit den Speicherbedarf - zu tiefe Rekursion (etwa n=10000n=10000n=10000) löst in Python einen `RecursionError` bzw. einen Stack Overflow aus.
Wie teuer Rekursion werden kann, zeigt der Rekursionsbaum. Beim naiven Fibonacci F(n)=F(n−1)+F(n−2)F(n)=F(n-1)+F(n-2)F(n)=F(n−1)+F(n−2) verzweigt jeder Aufruf in zwei, der Baum hat ≈φn\approx \varphi^{n}≈φn Knoten, und Teilprobleme werden mehrfach berechnet ( zeigt, wie fib(2)fib(2)fib(2) doppelt auftaucht). Daher ist die naive Laufzeit exponentiell, nicht linear.

Rekursionsbaum von fib(4)

Rekursionsbaum fib(4)Baumdiagramm, 4 Pfade, Daten: fib(3) → fib(2) → fib(1); fib(3) → fib(2) → fib(0); fib(3) → fib(1); fib(2)fib(2)fib(3)fib(4)fib(1)fib(0)fib(1)fib(2)
Abb. 2Jeder Aufruf verzweigt in zwei; fib(2) wird zweimal berechnet (hervorgehoben) - die Redundanz motiviert Memoization.
Das Heilmittel ist Memoization: einmal berechnete Werte in einer Tabelle merken, sodass jeder Teilwert nur einmal entsteht - das senkt Fibonacci von O(φn)O(\varphi^{n})O(φn) auf O(n)O(n)O(n). Allgemein sind iterative Lösungen meist speicherärmer (O(1)O(1)O(1) statt O(n)O(n)O(n) Stack), rekursive oft lesbarer. Endrekursion (Tail Recursion), bei der der Selbstaufruf die letzte Aktion ist, können viele Compiler in eine Schleife umwandeln - Python tut das allerdings nicht.
Klassische rekursive Verfahren sind Fakultät, Fibonacci, Türme von Hanoi, Quicksort, Mergesort und Baumtraversierungen. Typische Fehler: den Basisfall vergessen (Endlosrekursion), das `return` in der rekursiven Funktion weglassen, oder naives Fibonacci für effizient halten. In der Prüfung immer Basis- und Rekursionsfall explizit benennen und Tiefe bzw. Aufrufzahl an einem kleinen Beispiel begründen.
n!={1,n=0n⋅(n−1)!,n>0n! = \begin{cases} 1, & n = 0 \\ n \cdot (n-1)!, & n > 0 \end{cases}n!={1,n⋅(n−1)!,​n=0n>0​

Rekursive Definition der Fakultät

F(n)=F(n−1)+F(n−2), F(0)=0, F(1)=1F(n) = F(n-1) + F(n-2),\ F(0) = 0,\ F(1) = 1F(n)=F(n−1)+F(n−2), F(0)=0, F(1)=1

Fibonacci-Rekurrenz

Musterbeispiel

Fibonacci - rekursiv vs. memoization

Implementiere `fib(n)` rekursiv und mit Memoization in Python.

  1. 01Naive Rekursion

    ```python def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) ``` Laufzeit T(n)=T(n−1)+T(n−2)+1∈O(φn)T(n) = T(n-1)+T(n-2)+1 \in O(\varphi^{n})T(n)=T(n−1)+T(n−2)+1∈O(φn) mit φ=1+52\varphi=\tfrac{1+\sqrt 5}{2}φ=21+5​​.

  2. 02Memoization

    ```python from functools import lru_cache @lru_cache def fib(n): return n if n < 2 else fib(n-1)+fib(n-2) ``` Laufzeit O(n)O(n)O(n), Speicher O(n)O(n)O(n).

  3. 03Iterativ

    ```python def fib(n): a, b = 0, 1 for _ in range(n): a, b = b, a+b return a ``` Laufzeit O(n)O(n)O(n), Speicher O(1)O(1)O(1).

Ergebnis: Rekursion ist elegant, aber ohne Caching zu langsam; Memoization oder Iteration sind die richtigen Lösungen für grosse nnn.

Schritt-für-Schritt Erklärung3 Schritte
  1. 1

    Rekursion zerlegt ein Problem in eine kleinere Version desselben Problems plus einen Basisfall.

  2. 2

    Der Call-Stack ist die Daten-struktur, die Rekursion überhaupt erst möglich macht.

  3. 3

    Memoization speichert berechnete Werte und verwandelt exponentielle Rekursion in lineare Laufzeit.

SRDP-Aufgaben

SelbsttestAus der Fragenbank7 Punkte

Aufgabenstellung

Beschreibe das Prinzip der Rekursion und veranschauliche es am Beispiel der Fakultätsfunktion. Implementiere die Funktion in einer gewählten Programmiersprache und erläutere ihre Laufzeit sowie Speicherbedarf.

Maturafokus

  • Basisfall und Rekursionsfall stets explizit benennen.
  • Anzahl Aufrufe und maximale Tiefe über kleines Beispiel begründen.
  • Bei Fibonacci auf die exponentielle naive Laufzeit hinweisen und Memoization als Heilmittel kennen.

Typische Fehler

  • Basisfall vergessen -> Endlosrekursion.
  • Rekursive Funktion gibt nichts zurück (`return` fehlt).
  • Naives Fibonacci wird als effizient bezeichnet.

Aktive Wiederholung

Schreibe eine rekursive Python-Funktion `fakultät(n)`. Erläutere, warum sie bei n=10000n=10000n=10000 in Python einen `RecursionError` auslösen kann.

Aktiv abrufen

Erinnere dich an die Kernpunkte — dann aufdecken.

Quellen: Cormen, Leiserson, Rivest, Stein: Introduction to Algorithms (CLRS) Kap. 2-4 (MIT Press)

§ 03

Sortierverfahren - Bubble, Insertion, Merge, Quicksort#

●●○StandardLPINF-Alg-3.1

Logarithmisches Wachstum O(log n) bei wachsendem n

Logarithmisches Wachstum O(log n)Schaubild, Nullstellen bei x = 1, steigend, im Bereich x von 1 bis 10242004006008001000246810n = 646 SchritteSchritte (relativ)n
Abb. 5Eine Verdopplung von n erhöht die Schrittzahl nur um eine Konstante - typisch für die binäre Suche. Markiert: n = 64 mit etwa 6 Schritten.

Kernpunkte

Sortieren ist das Standardproblem der Informatik - an ihm lassen sich alle Kernkonzepte zeigen: Verfahrensidee, Laufzeit, Speicher und Stabilität. Ein zentrales Ergebnis vorweg: Jedes vergleichsbasierte Verfahren braucht mindestens Ω(nlog⁡n)\Omega(n\log n)Ω(nlogn) Vergleiche. Das folgt aus einem Entscheidungsbaum-Argument - es gibt n!n!n! mögliche Anordnungen, jeder Vergleich halbiert die Restmenge, und log⁡2(n!)≈nlog⁡n\log_{2}(n!) \approx n\log nlog2​(n!)≈nlogn.
Bubble Sort vergleicht benachbarte Elemente und tauscht sie, bis nichts mehr zu tauschen ist - sehr einfach, aber im Mittel und Worst Case O(n2)O(n^{2})O(n2). Insertion Sort fügt jedes neue Element an die richtige Stelle des bereits sortierten Präfix ein; ebenfalls O(n2)O(n^{2})O(n2), aber nur O(n)O(n)O(n) im Best Case (fast sortierte Daten) und mit geringem Overhead - daher ideal für kleine nnn.
Mergesort ist Divide-and-Conquer: Das Array wird halbiert, beide Hälften rekursiv sortiert und dann in Linearzeit verschmolzen (). Die Rekurrenz T(n)=2T(n/2)+nT(n)=2T(n/2)+nT(n)=2T(n/2)+n löst sich zu O(nlog⁡n)O(n\log n)O(nlogn), und zwar in allen Fällen. Der Preis ist O(n)O(n)O(n) Zusatzspeicher fürs Mischen; dafür ist Mergesort stabil.

Mergesort - Divide-and-Conquer Baum

Mergesort-BaumBaumdiagramm, 7 Pfade, Daten: [38,27,43,3] → [38,27] → [38]; [38,27,43,3] → [38,27] → [27]; [38,27,43,3] → [43,3] → [43]; [38,27,43,3] → [43,3] → [3]; [9,82,10] → [9,82] → [9]; [9,82,10] → [9,82] → [82]; [9,82,10] → [10][38,27][43,3][38,27,43,3][9,82][9,82,10][38,27,43,3,9,82,10][38][27][43][3][9][82][10]
Abb. 3Divide: das Array wird rekursiv halbiert bis zu Einzelelementen. Conquer (bottom-up): [27,38]+[3,43] ergibt [3,27,38,43], [9,82]+[10] ergibt [9,10,82], am Ende [3,9,10,27,38,43,82].
Quicksort wählt ein Pivot und partitioniert das Array in „<<< Pivot" und „≥\geq≥ Pivot" (), dann rekursiv weiter. Im Mittel O(nlog⁡n)O(n\log n)O(nlogn) und in-place (wenig Speicher), im Worst Case aber O(n2)O(n^{2})O(n2) - etwa bei bereits sortiertem Array mit dem ersten Element als Pivot; randomisierte Pivots oder Median-of-three entschärfen das. Quicksort ist nicht stabil.

Quicksort - Partition mit Pivot

Quicksort-Partition (Pivot 5)Tabelle mit 9 Spalten und 2 Zeilen, Daten: a0 · a1 · a2 · a3 · a4 · a5 · a6 · a7; vor · 8 · 3 · 1 · 7 · 5 · 2 · 6 · 4; nach · 3 · 1 · 2 · 4 · 5 · 8 · 7 · 6, hervorgehobene Zelle: 5A0A1A2A3A4A5A6A7VOR83175264NACH31245876
Abb. 4Das Pivot 5 trennt das Array in „kleiner Pivot" (links) und „größer/gleich Pivot" (rechts) und steht danach an seiner endgültigen Position (Index a4). Mittel O(n log n), Worst Case O(n^2).
Stabilität heißt: Elemente mit gleichem Schlüssel behalten ihre relative Reihenfolge. Das ist beim mehrstufigen Sortieren wichtig (erst nach Vorname, dann stabil nach Nachname - sonst zerfällt die erste Ordnung). Stabil sind Mergesort und Insertion Sort, nicht stabil Quicksort und Heapsort.
In der Praxis nutzen Standardbibliotheken Timsort (Python `sorted`, Java `Arrays.sort` für Objekte), eine Hybride aus Mergesort und Insertion Sort, die natürliche bereits sortierte Läufe ausnutzt. Häufige Fehler: den Quicksort-Worst-Case mit O(nlog⁡n)O(n\log n)O(nlogn) angeben (richtig ist O(n2)O(n^{2})O(n2)), Mergesort als in-place bezeichnen (es braucht O(n)O(n)O(n)), oder Quicksort für stabil halten.
T(n)=2T ⁣(n2)+n∈O(nlog⁡n)T(n) = 2T\!\left(\tfrac{n}{2}\right) + n \in O(n\log n)T(n)=2T(2n​)+n∈O(nlogn)

Mergesort-Rekurrenz und Lösung

Musterbeispiel

Mergesort-Trace auf [38, 27, 43, 3, 9, 82, 10]

Sortiere [38, 27, 43, 3, 9, 82, 10] mit Mergesort und protokolliere die Merge-Schritte.

  1. 01Teilen 1

    Links [38,27,43,3] | Rechts [9,82,10].

  2. 02Teilen 2 (links)

    [38,27] und [43,3] werden zu je [27,38] und [3,43] gemergt.

  3. 03Merge linker Halbteile

    merge([27,38],[3,43]) = [3,27,38,43].

  4. 04Teilen 2 (rechts)

    [9,82] und [10]; merge ergibt [9,10,82].

  5. 05Finaler Merge

    merge([3,27,38,43],[9,10,82]) = [3,9,10,27,38,43,82].

Ergebnis: Sortiertes Array [3, 9, 10, 27, 38, 43, 82]. Laufzeit T(n)=2T(n/2)+n∈O(nlog⁡n)T(n) = 2T(n/2)+n \in O(n \log n)T(n)=2T(n/2)+n∈O(nlogn).

Schritt-für-Schritt Erklärung3 Schritte
  1. 1

    Sortieren ist das Standardbeispiel, an dem alle Konzepte zusammenkommen: Verfahren, Komplexität, Speicher und Stabilität.

    Mergesort - Divide-and-Conquer Baum

    Mergesort-BaumBaumdiagramm, 7 Pfade, Daten: [38,27,43,3] → [38,27] → [38]; [38,27,43,3] → [38,27] → [27]; [38,27,43,3] → [43,3] → [43]; [38,27,43,3] → [43,3] → [3]; [9,82,10] → [9,82] → [9]; [9,82,10] → [9,82] → [82]; [9,82,10] → [10][38,27][43,3][38,27,43,3][9,82][9,82,10][38,27,43,3,9,82,10][38][27][43][3][9][82][10]
    Abb.Divide: das Array wird rekursiv halbiert bis zu Einzelelementen. Conquer (bottom-up): [27,38]+[3,43] ergibt [3,27,38,43], [9,82]+[10] ergibt [9,10,82], am Ende [3,9,10,27,38,43,82].
  2. 2

    Mergesort teilt das Array bis auf Einzelelemente und fädelt sie sortiert zusammen - daher die garantiert logarithmische Tiefe.

  3. 3

    Quicksort ist schnell, weil die Partition in-place arbeitet, aber er kann bei schlechter Pivotwahl quadratisch werden.

    Quicksort - Partition mit Pivot

    Quicksort-Partition (Pivot 5)Tabelle mit 9 Spalten und 2 Zeilen, Daten: a0 · a1 · a2 · a3 · a4 · a5 · a6 · a7; vor · 8 · 3 · 1 · 7 · 5 · 2 · 6 · 4; nach · 3 · 1 · 2 · 4 · 5 · 8 · 7 · 6, hervorgehobene Zelle: 5A0A1A2A3A4A5A6A7VOR83175264NACH31245876
    Abb.Das Pivot 5 trennt das Array in „kleiner Pivot" (links) und „größer/gleich Pivot" (rechts) und steht danach an seiner endgültigen Position (Index a4). Mittel O(n log n), Worst Case O(n^2).

SRDP-Aufgaben

SelbsttestAus der Fragenbank7 Punkte

Aufgabenstellung

Vergleiche Insertion Sort und Mergesort hinsichtlich Idee, Laufzeit und Speicher. Wann würdest du Insertion Sort, wann Mergesort einsetzen?

Maturafokus

  • Trace eines Verfahrens auf einem 6-8-Elemente-Array prozedural niederschreiben.
  • Worst/Best/Average Case auseinanderhalten und mit Beispielen begründen.
  • Begründung warum Vergleichssortierung mindestens Ω(nlog⁡n)\Omega(n\log n)Ω(nlogn) Vergleiche braucht (Entscheidungsbaum-Argument).

Typische Fehler

  • Quicksort-Worst-Case wird mit O(nlog⁡n)O(n \log n)O(nlogn) angegeben (richtig ist O(n2)O(n^{2})O(n2)).
  • Mergesort als in-place beschrieben (braucht aber O(n)O(n)O(n) Speicher).
  • Stabilität wird ignoriert und Quicksort wird fälschlich als stabil bezeichnet.

Aktive Wiederholung

Sortiere [5, 2, 9, 1, 5, 6] mit Insertion Sort und protokolliere die ersten drei Iterationen. Wie oft wird vergleichen und wie oft getauscht?

Aktiv abrufen

Erinnere dich an die Kernpunkte — dann aufdecken.

Quellen: Knuth: The Art of Computer Programming, Vol. 3 - Sorting and Searching (Addison-Wesley) · OpenDSA - Sorting Algorithms (Virginia Tech)

§ 04

Suchverfahren - linear und binaer#

●○○BasisLPINF-Alg-3.2

Kernpunkte

Suchen heißt: in einer Datenmenge ein Element mit gegebenem Schlüssel finden. Welche Methode richtig ist, hängt entscheidend davon ab, ob die Daten geordnet sind - das ist der rote Faden dieses Abschnitts ( vergleicht das Wachstum beider Verfahren).

Lineare vs. binäre Suche - Vergleichsschritte

Linear vs. binärSchaubild von O(n), steigend, im Bereich x von 1 bis 64, Schaubild von O(log n), Nullstellen bei x = 1, steigend, im Bereich x von 1 bis 64102030405060102030405060706O(n)O(log n)Schritten
Abb. 6Die lineare Suche wächst mit nnn, die binäre nur mit log⁡2n\log_{2} nlog2​n: bei n=64n=64n=64 genügen 6 statt 64 Vergleiche.
Die lineare Suche prüft der Reihe nach jedes Element; sie stellt keine Voraussetzung an die Reihenfolge und braucht im Worst Case nnn Vergleiche, also O(n)O(n)O(n). Für unsortierte oder als Stream eintreffende Daten bleibt sie der Standard.
Die binäre Suche setzt ein sortiertes Array voraus und halbiert in jedem Schritt das Suchintervall: Man vergleicht mit dem mittleren Element und verwirft die Hälfte, in der der Wert nicht liegen kann. So sinkt das Restproblem n→n/2→n/4→⋯→1n \to n/2 \to n/4 \to \dots \to 1n→n/2→n/4→⋯→1; die Rekurrenz T(n)=T(n/2)+1T(n)=T(n/2)+1T(n)=T(n/2)+1 ergibt O(log⁡n)O(\log n)O(logn). Konkret genügen bei n=1 000 000n=1\,000\,000n=1000000 nur ⌈log⁡2(n+1)⌉=20\lceil \log_{2}(n+1) \rceil = 20⌈log2​(n+1)⌉=20 Vergleiche statt bis zu einer Million.
Die Tücke liegt im Detail: mid=(low+high)/2mid=(low+high)/2mid=(low+high)/2 (besser low+(high−low)/2low+(high-low)/2low+(high−low)/2 gegen Überlauf), und die Grenzen müssen je nach Treffer korrekt verschoben werden (low=mid+1low=mid+1low=mid+1 bzw. high=mid−1high=mid-1high=mid−1), sonst entsteht eine Endlosschleife oder ein Off-by-one. Auf einem unsortierten Array liefert die binäre Suche schlicht falsche Ergebnisse.
Für gleichverteilte, sortierte Daten schätzt die Interpolationssuche die Position (wie beim Aufschlagen eines Telefonbuchs) und erreicht im Mittel O(log⁡log⁡n)O(\log \log n)O(loglogn). Hashtabellen suchen sogar in erwartetem O(1)O(1)O(1) - asymptotisch besser als binäre Suche -, kosten aber zusätzlichen Speicher und brauchen eine gute Hashfunktion.
Faustregel: lineare Suche für kleine, unsortierte oder streamende Daten; binäre Suche für große, sortierte, statische Bestände; Hashtabelle für sehr häufige Zugriffe bei vorhandenem Speicher. Häufige Fehler: binäre Suche auf unsortierte Daten anwenden, oder „logarithmisch ist langsamer als linear" - tatsächlich ist O(log⁡n)O(\log n)O(logn) dramatisch schneller als O(n)O(n)O(n).
Tbin(n)=T(n/2)+1∈O(log⁡n)T_{\text{bin}}(n) = T(n/2) + 1 \in O(\log n)Tbin​(n)=T(n/2)+1∈O(logn)

Rekurrenz der binären Suche

Musterbeispiel

Binäre Suche im sortierten Array

Finde mit binärer Suche den Wert 23 im Array [3, 7, 12, 18, 23, 31, 47, 55].

  1. 01Initial

    low = 0, high = 7. Pivot mid = (0+7)/2 = 3 -> a[3] = 18 < 23 -> rechts weitersuchen.

  2. 02Iteration 2

    low = 4, high = 7. mid = 5 -> a[5] = 31 > 23 -> links weitersuchen.

  3. 03Iteration 3

    low = 4, high = 4. mid = 4 -> a[4] = 23 == Suchwert. Index 4 zurückgeben.

Ergebnis: Index 4 nach 3 Vergleichen; allgemein O(log⁡n)O(\log n)O(logn) Schritte für nnn Elemente.

Schritt-für-Schritt Erklärung3 Schritte
  1. 1

    Die binaere Suche ist das Schulbuchbeispiel für logarithmische Laufzeit.

  2. 2

    Bei jeder Halbierung sinkt das Restproblem auf n/2n/2n/2, n/4n/4n/4, ... bis 111.

  3. 3

    Auf unsortierten Daten musst du linear suchen oder zuerst sortieren - das kostet O(nlog⁡n)O(n\log n)O(nlogn).

SRDP-Aufgaben

SelbsttestAus der Fragenbank7 Punkte

Aufgabenstellung

Erkläre die binaere Suche im Vergleich zur linearen Suche. Implementiere sie iterativ und nenne Voraussetzungen und Laufzeit.

Maturafokus

  • Trace mit konkretem Suchwert protokollieren (low, high, mid in jeder Iteration).
  • Sicher die Voraussetzung "sortiert" benennen.
  • Komplexitätsvergleich linear vs. binaer mit numerischen Beispielen.

Typische Fehler

  • Binäre Suche wird auf unsortiertes Array angewendet.
  • Off-by-one Fehler bei `mid = (low+high)/2` - bei `high-low+1` an Bedingung denken.
  • Verwechslung von linearer und binärer Komplexität ("logarithmisch ist langsamer als linear").

Aktive Wiederholung

Schreibe eine iterative binaere Suche in JavaScript. Wie viele Iterationen sind im Worst Case bei einer Million Elementen nötig?

Aktiv abrufen

Erinnere dich an die Kernpunkte — dann aufdecken.

Quellen: Sedgewick & Wayne: Algorithms, 4. Auflage (Addison-Wesley)

§ 05

Big-O, Master-Theorem und Grenzen#

●●●VertiefungLPINF-Alg-4.1LPINF-Alg-4.2

Mergesort - Divide-and-Conquer Baum

Mergesort-BaumBaumdiagramm, 7 Pfade, Daten: [38,27,43,3] → [38,27] → [38]; [38,27,43,3] → [38,27] → [27]; [38,27,43,3] → [43,3] → [43]; [38,27,43,3] → [43,3] → [3]; [9,82,10] → [9,82] → [9]; [9,82,10] → [9,82] → [82]; [9,82,10] → [10][38,27][43,3][38,27,43,3][9,82][9,82,10][38,27,43,3,9,82,10][38][27][43][3][9][82][10]
Abb. 8Divide: das Array wird rekursiv halbiert bis zu Einzelelementen. Conquer (bottom-up): [27,38]+[3,43] ergibt [3,27,38,43], [9,82]+[10] ergibt [9,10,82], am Ende [3,9,10,27,38,43,82].

Kernpunkte

Will man Algorithmen vergleichen, ohne Hardware und Programmiersprache zu vermischen, zählt man nicht Sekunden, sondern wie die Schrittzahl mit der Eingabegröße nnn wächst. Die Big-O-Notation macht das präzise und ist damit die gemeinsame Sprache der Laufzeitanalyse ( zeigt die wichtigsten Klassen im Vergleich).

Wachstum der Komplexitätsklassen

KomplexitätsklassenSchaubild von log n, Nullstellen bei x = 1, steigend, im Bereich x von 1 bis 7, Schaubild von n, steigend, im Bereich x von 1 bis 7, Schaubild von n^2, steigend, im Bereich x von 1 bis 7, Schaubild von 2^n, steigend, im Bereich x von 1 bis 7123456720406080100120140log nnn22nOperationenn
Abb. 7Logarithmisch, linear, quadratisch und exponentiell im Vergleich - das exponentielle 2n2^{n}2n enteilt allen anderen.
Formal ist f∈O(g)f \in O(g)f∈O(g), wenn es Konstanten c>0c>0c>0 und n0n_{0}n0​ gibt mit f(n)≤c g(n)f(n) \leq c\,g(n)f(n)≤cg(n) für alle n≥n0n \geq n_{0}n≥n0​. Big-O ist also eine obere asymptotische Schranke: Konstante Faktoren und Terme niedrigerer Ordnung fallen weg, O(3n+5)=O(n)O(3n+5)=O(n)O(3n+5)=O(n). Daneben stehen Ω(g)\Omega(g)Ω(g) (untere Schranke), Θ(g)\Theta(g)Θ(g) (gleiches Wachstum, obere und untere zugleich) und o(g)o(g)o(g) (strikt langsamer wachsend).
Die geläufige Hierarchie lautet O(1)⊂O(log⁡n)⊂O(n)⊂O(nlog⁡n)⊂O(n2)⊂O(2n)⊂O(n!)O(1) \subset O(\log n) \subset O(n) \subset O(n\log n) \subset O(n^{2}) \subset O(2^{n}) \subset O(n!)O(1)⊂O(logn)⊂O(n)⊂O(nlogn)⊂O(n2)⊂O(2n)⊂O(n!). Anschaulich (): konstante und logarithmische Verfahren bleiben selbst bei Milliarden Elementen schnell, quadratische schaffen höchstens Hunderttausende, exponentielle nur Dutzende - das 2n2^{n}2n enteilt allen anderen.
Für Divide-and-Conquer-Rekurrenzen T(n)=a T(n/b)+f(n)T(n) = a\,T(n/b) + f(n)T(n)=aT(n/b)+f(n) liefert das Master-Theorem die Lösung über den Vergleich von f(n)f(n)f(n) mit nlog⁡ban^{\log_{b}a}nlogb​a: Dominiert nlog⁡ban^{\log_{b}a}nlogb​a (Fall 1), ist T∈Θ(nlog⁡ba)T \in \Theta(n^{\log_{b}a})T∈Θ(nlogb​a); sind beide gleich groß (Fall 2), Θ(nlog⁡balog⁡n)\Theta(n^{\log_{b}a}\log n)Θ(nlogb​alogn); dominiert fff (Fall 3), Θ(f(n))\Theta(f(n))Θ(f(n)). Für Mergesort (a=2, b=2, f=na=2,\,b=2,\,f=na=2,b=2,f=n) ist nlog⁡22=n=fn^{\log_{2}2}=n=fnlog2​2=n=f, also Fall 2 und Θ(nlog⁡n)\Theta(n\log n)Θ(nlogn) (siehe Beispiel).
Komplexität fragt „wie teuer?", die Berechenbarkeit fragt „überhaupt lösbar?". Nicht jedes Problem ist algorithmisch entscheidbar - das Halteproblem ist das berühmte Gegenbeispiel. Big-O sagt nichts über die Lösbarkeit, nur über den Aufwand lösbarer Probleme.
Häufige Fehler: Konstanten in Big-O behalten; das Master-Theorem auf Rekurrenzen ohne Divide-and-Conquer-Form anwenden; oder exponentielle Verfahren für „in der Praxis lösbar" halten. Und stets bedenken: Big-O gilt asymptotisch - für kleine nnn kann ein O(n2)O(n^{2})O(n2)-Verfahren ein O(nlog⁡n)O(n\log n)O(nlogn)-Verfahren wegen kleinerer Konstanten schlagen.
f(n)∈O(g(n))  ⟺  ∃ c>0, n0≥0:∀ n≥n0:f(n)≤c⋅g(n)f(n) \in O(g(n)) \iff \exists\, c>0,\, n_{0}\geq 0 : \forall\, n \geq n_{0} : f(n) \leq c\cdot g(n)f(n)∈O(g(n))⟺∃c>0,n0​≥0:∀n≥n0​:f(n)≤c⋅g(n)

Big-O Notation - obere asymptotische Schranke

T(n)=a⋅T ⁣(nb)+f(n),a≥1, b>1T(n) = a\cdot T\!\left(\tfrac{n}{b}\right) + f(n),\quad a\geq 1,\, b>1T(n)=a⋅T(bn​)+f(n),a≥1,b>1

Master-Theorem - Rekurrenzform für Divide-and-Conquer

Logarithmisches Wachstum O(log n) bei wachsendem n

Logarithmisches Wachstum O(log n)Schaubild, Nullstellen bei x = 1, steigend, im Bereich x von 1 bis 10242004006008001000246810n = 646 SchritteSchritte (relativ)n
Abb. 9Eine Verdopplung von n erhöht die Schrittzahl nur um eine Konstante - typisch für die binäre Suche. Markiert: n = 64 mit etwa 6 Schritten.
Musterbeispiel

Master-Theorem auf Mergesort anwenden

Bestimme die Lösung der Rekurrenz T(n)=2T(n/2)+nT(n) = 2T(n/2) + nT(n)=2T(n/2)+n mit dem Master-Theorem.

  1. 01Parameter ablesen

    a=2a=2a=2, b=2b=2b=2, f(n)=nf(n)=nf(n)=n.

  2. 02Vergleichsgröße

    log⁡ba=log⁡22=1\log_{b} a = \log_{2} 2 = 1logb​a=log2​2=1; also nlog⁡ba=nn^{\log_{b}a} = nnlogb​a=n.

  3. 03Fall prüfen

    f(n)=n=Θ(n1)f(n)=n=\Theta(n^{1})f(n)=n=Θ(n1) -> Fall 2 des Master-Theorems.

  4. 04Lösung anwenden

    T(n)=Θ(nlog⁡ba⋅log⁡n)=Θ(nlog⁡n)T(n) = \Theta(n^{\log_{b} a} \cdot \log n) = \Theta(n \log n)T(n)=Θ(nlogb​a⋅logn)=Θ(nlogn).

Ergebnis: Mergesort hat asymptotische Laufzeit T(n)∈Θ(nlog⁡n)T(n) \in \Theta(n \log n)T(n)∈Θ(nlogn) im Worst, Average und Best Case.

Schritt-für-Schritt Erklärung3 Schritte
  1. 1

    Big-O sagt dir, wie sich eine Laufzeit verhält, wenn du die Eingabegröße verdoppelst.

    Logarithmisches Wachstum O(log n) bei wachsendem n

    Logarithmisches Wachstum O(log n)Schaubild, Nullstellen bei x = 1, steigend, im Bereich x von 1 bis 10242004006008001000246810n = 646 SchritteSchritte (relativ)n
    Abb.Eine Verdopplung von n erhöht die Schrittzahl nur um eine Konstante - typisch für die binäre Suche. Markiert: n = 64 mit etwa 6 Schritten.
  2. 2

    Das Master-Theorem ist die schnellste Methode, Divide-and-Conquer-Rekurrenzen zu lösen.

  3. 3

    Achte darauf, dass Big-O nur asymptotisch gilt - für kleine Eingaben kann ein quadratischer Algorithmus schneller sein als ein log-linearer.

SRDP-Aufgaben

SelbsttestAus der Fragenbank7 Punkte

Aufgabenstellung

Erläutere die Big-O-Notation und vergleiche die Laufzeitklassen O(1)O(1)O(1), O(log⁡n)O(\log n)O(logn), O(n)O(n)O(n), O(nlog⁡n)O(n \log n)O(nlogn) und O(n2)O(n^{2})O(n2) anhand konkreter Algorithmen. Diskutiere am Beispiel von Mergesort die Anwendung des Master-Theorems.

Maturafokus

  • Master-Theorem anhand der drei Fälle (mit konkretem a,b,fa, b, fa,b,f) anwenden.
  • Konstante Faktoren in Big-O weglassen, aber im Vergleich kleiner nnn erwähnen.
  • Bei Argumentationen klar Worst/Average/Best Case unterscheiden.

Typische Fehler

  • Konstanten in Big-O behalten (O(3n)=O(n)O(3n) = O(n)O(3n)=O(n)).
  • Master-Theorem auf nicht-Divide-and-Conquer-Rekurrenzen anwenden.
  • Exponentielles Wachstum als "praktisch lösbar" einstufen.

Aktive Wiederholung

Bestimme mit dem Master-Theorem die Lösung der Rekurrenzen T(n)=3T(n/2)+n2T(n)=3T(n/2)+n^{2}T(n)=3T(n/2)+n2 und T(n)=4T(n/2)+nT(n)=4T(n/2)+nT(n)=4T(n/2)+n. Wie lautet die Komplexität jeweils?

Aktiv abrufen

Erinnere dich an die Kernpunkte — dann aufdecken.

Quellen: CLRS: Introduction to Algorithms, Kapitel 3 und 4 (MIT Press)

§ 06

Greedy- und Dynamic-Programming-Verfahren#

●●●VertiefungLPINF-Alg-5.1

Kernpunkte

Manche Optimierungsprobleme lassen sich nicht durch blindes Ausprobieren lösen, weil es zu viele Möglichkeiten gibt. Zwei mächtige Entwurfsstrategien helfen: Greedy und Dynamic Programming. Sie unterscheiden sich darin, ob eine lokal beste Entscheidung schon global optimal ist.
Greedy-Algorithmen treffen in jedem Schritt die lokal beste Wahl und revidieren sie nie. Das ist einfach und schnell, aber nur garantiert optimal, wenn das Problem die passende Struktur (ein Matroid) hat. Erfolgreiche Beispiele sind die Aktivitätenauswahl, Huffman-Codes, minimale Spannbäume (Prim, Kruskal) und Coin Change in kanonischen Münzsystemen.
Beim Coin Change sieht man die Grenze von Greedy: Münzen {1, 3, 4}\{1,\,3,\,4\}{1,3,4}, Ziel 666 - Greedy nimmt 4+1+14+1+14+1+1 (3 Münzen), optimal sind 3+33+33+3 (2 Münzen). Lokal optimal ist eben nicht immer global optimal; genau so ein Gegenbeispiel sollte man in der Prüfung parat haben.
Dynamic Programming (DP) löst solche Fälle, indem es das Problem in überlappende Teilprobleme zerlegt und jedes nur einmal berechnet (die Ergebnisse werden gespeichert). Voraussetzung sind zwei Eigenschaften: optimale Substruktur (die Gesamtlösung setzt sich aus optimalen Teillösungen zusammen) und überlappende Teilprobleme (dieselben Teilprobleme treten mehrfach auf).
Es gibt zwei Bauweisen: Top-down (Memoization) - die rekursive Lösung mit Cache - und Bottom-up (Tabelle) - die Teilprobleme in passender Reihenfolge iterativ füllen. Beim 0/1-Rucksack mit der Rekurrenz K(i,w)=max⁡(K(i−1,w), K(i−1,w−wi)+vi)K(i,w)=\max\bigl(K(i-1,w),\,K(i-1,w-w_{i})+v_{i}\bigr)K(i,w)=max(K(i−1,w),K(i−1,w−wi​)+vi​) füllt sich die DP-Tabelle zeilenweise (); das Ergebnis K(3,50)=220K(3, 50)=220K(3,50)=220 steht unten rechts.

Knapsack-DP-Tabelle (W=50)

Knapsack-DP-TabelleTabelle mit 7 Spalten und 4 Zeilen, Daten: i / W · 0 · 10 · 20 · 30 · 40 · 50; 0 · 0 · 0 · 0 · 0 · 0 · 0; 1 · 0 · 60 · 60 · 60 · 60 · 60; 2 · 0 · 60 · 100 · 160 · 160 · 160; 3 · 0 · 60 · 100 · 160 · 180 · 220, hervorgehobene Zelle: 220I / W01020304050000000010606060606020601001601601603060100160180220
Abb. 10Bottom-up gefüllte DP-Tabelle für Werte [60,100,120] und Gewichte [10,20,30]; das Optimum 220 steht unten rechts.
Die Laufzeit von DP ergibt sich aus der Tabellengröße mal Aufwand pro Zelle: O(n⋅W)O(n\cdot W)O(n⋅W) für 0/1-Knapsack - pseudopolynomiell, weil WWW als Zahlwert und nicht als Eingabelänge zählt. Klassische DP-Probleme sind Fibonacci, das Rucksackproblem, kürzeste Pfade (Bellman-Ford) und die Edit Distance. Häufige Fehler: Greedy auf nicht-kanonische Systeme anwenden, die Tabelle in falscher Reihenfolge füllen, oder Top-down ohne Memoization als DP ausgeben (dann wieder exponentiell).
K(i,w)=max⁡(K(i−1,w), K(i−1,w−wi)+vi)K(i, w) = \max\bigl(K(i-1, w),\, K(i-1, w - w_{i}) + v_{i}\bigr)K(i,w)=max(K(i−1,w),K(i−1,w−wi​)+vi​)

DP-Rekurrenz für 0/1-Knapsack

Musterbeispiel

0/1-Knapsack via DP

Werte [60,100,120][60, 100, 120][60,100,120], Gewichte [10,20,30][10, 20, 30][10,20,30], Kapazität W=50W=50W=50.

  1. 01DP-Tabelle initialisieren

    Tabelle KKK der Größe 4×514 \times 514×51; erste Zeile/Spalte = 0.

  2. 02Befüllen

    Für jedes Item iii und jede Kapazität www: K(i,w)=max⁡(K(i−1,w),K(i−1,w−wi)+vi)K(i,w) = \max(K(i-1,w), K(i-1, w-w_{i}) + v_{i})K(i,w)=max(K(i−1,w),K(i−1,w−wi​)+vi​), falls w≥wiw \geq w_{i}w≥wi​.

  3. 03Endergebnis ablesen

    K(3,50)=220K(3, 50) = 220K(3,50)=220 (Items 2 und 3).

Ergebnis: Maximaler Wert 220 EUR. Mit Backtracking auf der Tabelle lässt sich die optimale Auswahl rekonstruieren. Laufzeit O(n⋅W)O(n \cdot W)O(n⋅W) - pseudo-polynomiell.

Schritt-für-Schritt Erklärung3 Schritte
  1. 1

    Greedy ist verführerisch einfach - aber nur bei matroidischen Problemen garantiert optimal.

  2. 2

    DP ist die Klassiker-Antwort, wenn ein Problem optimale Teilstruktur und Überlappung hat.

  3. 3

    Memoization spart Zeit, DP-Tabelle spart Stack - wähle nach Problem.

SRDP-Aufgaben

SelbsttestAus der Fragenbank7 Punkte

Aufgabenstellung

Vergleiche Greedy-Algorithmen und Dynamic Programming. Erkläre an einem konkreten Beispiel, warum Greedy nicht immer das Optimum liefert.

Maturafokus

  • Greedy vs. DP unterscheiden: wann garantiert Greedy Optimum?
  • DP-Tabelle für Coin Change oder Knapsack ausfüllen.
  • Komplexität von DP herleiten (O(n⋅W)O(n \cdot W)O(n⋅W) für 0/1-Knapsack).

Typische Fehler

  • Greedy wird auf nicht-kanonisches Münzsystem angewendet (z.B. Münzen 1, 3, 4 - Greedy liefert 6 = 4+1+1, optimal wäre 3+3).
  • DP-Tabelle wird in falscher Reihenfolge aufgebaut.
  • Top-down ohne Memoization wird als DP verkauft (-> exponentiell).

Aktive Wiederholung

Löse das 0/1-Knapsack-Problem mit Werten [60,100,120][60, 100, 120][60,100,120], Gewichten [10,20,30][10, 20, 30][10,20,30] und Kapazität 505050 mittels DP-Tabelle.

Aktiv abrufen

Erinnere dich an die Kernpunkte — dann aufdecken.

Quellen: CLRS Kapitel 15 (DP) und 16 (Greedy) (MIT Press)

Inhalt

Abschnitt -- / 06

    • 01Kontrollstrukturen, Funktionen und Modularisierung○
    • 02Rekursion und Iteration◐
    • 03Sortierverfahren - Bubble, Insertion, Merge, Quicksort◐
    • 04Suchverfahren - linear und binaer○
    • 05Big-O, Master-Theorem und Grenzen●
    • 06Greedy- und Dynamic-Programming-Verfahren●

0/6 Gelesen

Aus den Notizen ins Training

INF-Alg - Algorithmen, Programmierung und Komplexität

Festige dieses Thema an passenden Aufgaben aus der Fragenbank.

~20
Min
4
Kompetenzen
Üben
Beispielfrage

Erkläre am Beispiel einer selbst gewählten Aufgabe die Bedeutung der drei elementaren Kontrollstrukturen Sequenz, Selektion und Iteration. Schreibe die Lösung in Pseudocode oder einer Programmiersprache deiner Wahl.

7 BE · 2022

Zur Fragenbank

Belege & Quellen

Quellen

CACM

  • Böhm/Jacopini: Flow diagrams, Turing machines and languages with only two formation rules

PSF

  • Python Software Foundation - Tutorial

MIT Press

  • Cormen, Leiserson, Rivest, Stein: Introduction to Algorithms (CLRS) Kap. 2-4

Addison-Wesley

  • Knuth: The Art of Computer Programming, Vol. 3 - Sorting and Searching
  • Sedgewick & Wayne: Algorithms, 4. Auflage

Virginia Tech

  • OpenDSA - Sorting Algorithms

Vorheriges Thema

INF-Daten - Informationssysteme, Codierung und Zahlensysteme

Nächstes Thema

INF-DS - Datenstrukturen

EuraStudy·Notizen T·02·MMXXVI

Weiter mit dem nächsten Thema — der Lernpfad bleibt erhalten.