Zuletzt aktualisiert am 16.12.2025 5 Minuten Lesezeit

Big-O-Notation

Die Big-O-Notation ist ein mathematisches Werkzeug zur Beschreibung des Wachstumsverhaltens von Algorithmen. Sie gibt an, wie sich die Laufzeit oder der Speicherbedarf eines Algorithmus verhält, wenn die Eingabegröße wächst. Für dich als IT-Auszubildender ist die Big-O-Notation ein unverzichtbares Konzept, um die Effizienz von Code zu bewerten und verschiedene Lösungsansätze zu vergleichen.

Was bedeutet Big-O-Notation?

Die Big-O-Notation, auch Landau-Notation genannt, beschreibt die obere Schranke der Laufzeit eines Algorithmus. Sie beantwortet die Frage: "Wie verhält sich mein Algorithmus im schlimmsten Fall, wenn die Datenmenge sehr groß wird?" Dabei werden Konstanten und niedrigwertige Terme ignoriert, um sich auf das wesentliche Wachstumsverhalten zu konzentrieren.

Konkret bedeutet das: Wenn ein Algorithmus 3n² + 5n + 100 Operationen benötigt, ist seine Komplexität O(n²). Die Konstanten (3, 5, 100) und der lineare Term (5n) verschwinden, weil bei großen Eingabemengen nur der quadratische Term dominiert.

Geschichte und Ursprung

Die Notation wurde 1894 vom deutschen Mathematiker Paul Bachmann eingeführt und später von Edmund Landau populär gemacht – daher der alternative Name "Landau-Symbole". Ursprünglich für die Zahlentheorie entwickelt, ist sie heute ein Standardwerkzeug in der Informatik zur Analyse von Algorithmen.

Die wichtigsten Komplexitätsklassen

Die folgenden Komplexitätsklassen begegnen dir in der Praxis am häufigsten. Sie sind von der besten zur schlechtesten Komplexität sortiert:

O(1) – Konstante Zeit

Die beste mögliche Komplexität. Die Ausführungszeit ist unabhängig von der Eingabegröße – egal ob du 10 oder 10 Millionen Elemente hast, die Operation dauert gleich lang.

Beispiele:

  • Zugriff auf ein Array-Element über Index: array[5]
  • Einfügen am Anfang einer verketteten Liste
  • Zugriff auf eine HashMap/Dictionary mit bekanntem Schlüssel
  • Prüfen, ob eine Zahl gerade oder ungerade ist

Verwandte Konzepte

Neben der Big-O-Notation gibt es weitere Landau-Symbole:

  • Omega (Ω): Beschreibt die untere Schranke (Best Case)
  • Theta (Θ): Beschreibt exaktes Wachstum (wenn obere und untere Schranke gleich sind)
  • Kleines o: Strikt langsamer wachsend als die Vergleichsfunktion

Quellen und weiterführende Links

Beispiele:

  • Lineare Suche in einem unsortierten Array
  • Summieren aller Elemente einer Liste
  • Finden des Maximums/Minimums
  • Einmaliges Durchlaufen einer Liste
// Summe berechnen: Jedes Element genau einmal besuchen
int summe = 0;
for (int i = 0; i < array.length; i++) {
    summe += array[i];
}

O(n log n) – Quasi-lineare Zeit

Typisch für effiziente Sortieralgorithmen. Wächst schneller als linear, aber deutlich langsamer als quadratisch. Gilt als sehr gute Komplexität für Sortierprobleme.

Beispiele:

  • Merge Sort (immer O(n log n))
  • Quick Sort (im Durchschnitt)
  • Heap Sort
  • Timsort (Python, Java)

O(n²) – Quadratische Zeit

Die Laufzeit wächst mit dem Quadrat der Eingabegröße. Verdoppelt sich die Eingabe, vervierfacht sich die Zeit. Bei großen Datenmengen problematisch, aber für kleine Eingaben oft akzeptabel.

Beispiele:

  • Bubble Sort, Selection Sort, Insertion Sort
  • Verschachtelte Schleifen über dieselbe Datenmenge
  • Vergleich aller Paare in einer Liste
// Typisches O(n²)-Muster: Verschachtelte Schleifen
for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        // n * n = n² Operationen
    }
}

O(2^n) – Exponentielle Zeit

Die Laufzeit verdoppelt sich mit jedem zusätzlichen Element. Bereits bei n = 30 werden über eine Milliarde Operationen benötigt. Solche Algorithmen sind nur für sehr kleine Eingaben praktikabel.

Beispiele:

  • Naive rekursive Berechnung der Fibonacci-Zahlen
  • Generierung aller Teilmengen einer Menge
  • Brute-Force-Lösung des Rucksackproblems
// Naive Fibonacci: Extrem ineffizient!
int fib(int n) {
    if (n <= 1) return n;
    return fib(n-1) + fib(n-2);  // Doppelter rekursiver Aufruf
}
// fib(40) benötigt über 1 Milliarde Aufrufe!

Komplexitätsklassen im Vergleich

Die folgende Tabelle zeigt, wie unterschiedlich die Komplexitätsklassen bei wachsender Eingabegröße skalieren:

n O(1) O(log n) O(n) O(n log n) O(n²) O(2^n)
10 1 3 10 33 100 1.024
100 1 7 100 664 10.000 10^30
1.000 1 10 1.000 9.966 1.000.000
10.000 1 13 10.000 132.877 100.000.000

Best Case, Average Case, Worst Case

Bei der Algorithmenanalyse unterscheidet man drei Szenarien:

  • Best Case (bester Fall): Die günstigste Eingabe, z.B. bei Insertion Sort ein bereits sortiertes Array → O(n)
  • Average Case (Durchschnittsfall): Das erwartete Verhalten bei typischen Eingaben
  • Worst Case (schlechtester Fall): Die ungünstigste Eingabe, z.B. bei Quick Sort ein bereits sortiertes Array mit schlechter Pivot-Wahl → O(n²)

Die Big-O-Notation beschreibt üblicherweise den Worst Case, da er die sicherste Garantie bietet. Bei kritischen Systemen ist es wichtig zu wissen, dass ein Algorithmus auch im schlimmsten Fall schnell genug ist.

Warum ist Big-O-Notation wichtig?

Für die Softwareentwicklung ist die Big-O-Notation aus mehreren Gründen unverzichtbar:

  • Skalierbarkeit einschätzen: Ein Algorithmus, der bei 100 Datensätzen funktioniert, kann bei 1 Million versagen
  • Vergleich von Lösungen: Verschiedene Implementierungen objektiv bewerten
  • Engpässe identifizieren: Performance-Probleme frühzeitig erkennen
  • Bewerbungsgespräche: Standardfrage in technischen Interviews
  • IHK-Prüfungen: Komplexitätsanalyse ist Prüfungsstoff für Fachinformatiker Anwendungsentwicklung

Praktische Tipps zur Komplexitätsanalyse

Mit diesen Faustregeln kannst du die Komplexität von Code schnell einschätzen:

  1. Einfache Schleife über n Elemente → O(n)
  2. Verschachtelte Schleifen → Multipliziere die Komplexitäten: O(n) × O(n) = O(n²)
  3. Halbierung bei jedem Schritt (wie binäre Suche) → O(log n)
  4. Divide and Conquer mit linearem Merge → O(n log n)
  5. Rekursion mit mehreren Aufrufen → Oft exponentiell, prüfe genau!
  6. Sequentielle Operationen → Addiere die Komplexitäten, die höchste dominiert

Big-O in der Praxis: Datenstrukturen

Die Wahl der richtigen Datenstruktur beeinflusst die Komplexität deiner Operationen erheblich:

Operation Array Verkettete Liste Hash-Map Binärbaum
Zugriff per Index O(1) O(n) - -
Suche O(n) O(n) O(1)* O(log n)
Einfügen am Ende O(1)* O(1) O(1)* O(log n)
Einfügen am Anfang O(n) O(1) - -
Löschen O(n) O(1)** O(1)* O(log n)

*amortisiert | **wenn Position bekannt