Zum Hauptinhalt springen

1.2.4 Laufzeit & 1.2.5 O-Kalkül

1.2.4 Laufzeit von Algorithmen​

Definition

Laufzeit eines Algorithmus = Anzahl der ausgeführten primitiven Operationen. Eine primitive Operation entspricht einem Zeitschritt.

Die Laufzeit hängt von der Eingabegröße nn ab (z.B. Anzahl der Punkte). Sie ist also eine Funktion von nn, die Laufzeitfunktion T(n)T(n), etwa

T(n)=an2+bn+cfu¨r Konstanten a,b,c.T(n) = a n^2 + bn + c\qquad\text{für Konstanten } a,b,c.

Best, Worst, Average Case​

Bei gleicher Eingabegröße kann die Laufzeit je nach konkreter Eingabe unterschiedlich sein:

AnalyseFrageBeispiel Jarvis' March (§2.5)
Best Caseschnellste Eingabe der Größe nn?Hülle ist ein Dreieck: O(n)O(n)
Worst Caselangsamste Eingabe der Größe nn?alle Punkte auf der Hülle: O(n2)O(n^2)
Average CaseErwartungswert über eine Verteilung der Eingaben?gleichverteilte Punkte im Quadrat: O(nlog⁡n)O(n\log n)

In der Vorlesung ist ohne Zusatz meist der Worst Case gemeint. Er ist eine Garantie.

Nur die Ordnung zählt​

Die exakte Laufzeitfunktion ist oft sehr kompliziert und hängt von Details ab (Compiler, Rechner, welche Operation man wie zählt). Deshalb betrachtet man nur die Ordnung (Größenordnung):

  • T(n)=an2+bn+cT(n)=an^2+bn+c hat die Ordnung n2n^2.
  • T(n)=an+bT(n)=an+b hat die Ordnung nn.

1.2.5 O-Kalkül (Landau-Symbole)​

Benannt nach Edmund Landau (1877–1938).

Motivation: Um die Komplexität von Problemen und Algorithmen zu vergleichen, muss man Laufzeitfunktionen vergleichen. Relevant ist das asymptotische Wachstum: Wie verhalten sich f(n)f(n) und g(n)g(n) für große nn? „Welche Funktion gewinnt das Rennen?“

Vorteile:

  • Konstante Faktoren sind irrelevant (ob ein Schritt 2 oder 5 ns dauert, ist egal).
  • Bei Polynomen zählt nur der größte Exponent.

Big-O: obere Schranke (≤)​

O(g(n))={f(n):∃ c>0, n0>0 mit 0≤∣f(n)∣≤c ∣g(n)∣  ∀n≥n0}O(g(n)) = \{f(n) : \exists\, c>0,\ n_0>0 \text{ mit } 0\le\lvert f(n)\rvert\le c\,\lvert g(n)\rvert\ \ \forall n\ge n_0\}

In Worten: ff wächst höchstens so schnell wie gg. Ab einer Stelle n0n_0 liegt ff immer unter einem festen Vielfachen von gg.

Schreibweise: f(n)=O(g(n))f(n)=O(g(n)) statt f(n)∈O(g(n))f(n)\in O(g(n)). Das „=“ ist nur in dieser Richtung zu lesen, O(n2)=3nO(n^2)=3n ergibt keinen Sinn.

Beispiele mit Nachweis:

  • 3n=O(n2)3n=O(n^2): wähle c=3c=3, n0=1n_0=1, denn 3n≤3n23n\le 3n^2 für n≥1n\ge1. ✔
  • n2/2−3n=O(n2)n^2/2-3n = O(n^2): wähle c=12c=\tfrac12, n0=6n_0=6 (ab da ist n2/2−3n≥0n^2/2-3n\ge 0 und ≤n2/2\le n^2/2). ✔
  • 6n3≠O(n2)6n^3\neq O(n^2): 6n3≤cn2  ⟺  n≤c/66n^3\le cn^2 \iff n\le c/6 gilt für kein festes cc für alle großen nn. ✘

Zum Ausprobieren: Wähle ff und verändere cc. Grün markiert ist der Bereich ab n0n_0, in dem die Ungleichung gilt. Bei 6n36n^3 findet man für O(n2)O(n^2) kein cc, das bis zum rechten Rand hält – schieb nn hoch und es kippt wieder.

181523304620n₀ = 3
f(n) =
■ f(n) = n²/2 − 3n  ■ c·g(n) = 0.513·n²
Im Bereich gilt |f(n)| ≤ c·g(n) für alle n ≥ n₀ = 3 (grün). Tatsächlich gilt: n²/2 − 3n = O(n²) – es gibt also passende Konstanten.

Big-Omega: untere Schranke (≥)​

Ω(g(n))={f(n):∃ c>0, n0>0 mit 0≤c ∣g(n)∣≤∣f(n)∣  ∀n≥n0}\Omega(g(n)) = \{f(n) : \exists\, c>0,\ n_0>0 \text{ mit } 0\le c\,\lvert g(n)\rvert\le\lvert f(n)\rvert\ \ \forall n\ge n_0\}

ff wächst mindestens so schnell wie gg.

  • 3n≠Ω(n2)3n\neq\Omega(n^2)
  • n2/2−3n=Ω(n2)n^2/2-3n=\Omega(n^2): wähle c=14c=\tfrac14, n0=12n_0=12 (dann n2/2−3n≥n2/4  ⟺  n≥12n^2/2-3n\ge n^2/4 \iff n\ge 12). ✔
  • 6n3=Ω(n2)6n^3=\Omega(n^2)

Typische Verwendung: untere Schranken für Probleme: „Jeder Algorithmus braucht mindestens Ω(nlog⁡n)\Omega(n\log n)“, siehe 2.3.

Big-Theta: exakte Ordnung (=)​

Θ(g(n))={f(n):∃ c1,c2>0, n0>0 mit 0≤c1∣g(n)∣≤∣f(n)∣≤c2∣g(n)∣  ∀n≥n0}\Theta(g(n)) = \{f(n) : \exists\, c_1,c_2>0,\ n_0>0 \text{ mit } 0\le c_1\lvert g(n)\rvert\le\lvert f(n)\rvert\le c_2\lvert g(n)\rvert\ \ \forall n\ge n_0\}

ff wächst genauso schnell wie gg: eingeklemmt zwischen zwei Vielfachen von gg. Äquivalent: f=O(g)f=O(g) und f=Ω(g)f=\Omega(g).

  • 3n≠Θ(n2)3n\neq\Theta(n^2)
  • n2/2−3n=Θ(n2)n^2/2-3n=\Theta(n^2) ✔
  • 6n3≠Θ(n2)6n^3\neq\Theta(n^2)

Small-o: echt kleiner​

o(g(n))={f(n):∀ c>0 ∃ n0>0 mit 0≤∣f(n)∣<c ∣g(n)∣  ∀n≥n0}o(g(n)) = \{f(n) : \forall\, c>0\ \exists\, n_0>0 \text{ mit } 0\le\lvert f(n)\rvert < c\,\lvert g(n)\rvert\ \ \forall n\ge n_0\}

Unterschied zu OO: Die Ungleichung muss für jedes noch so kleine cc gelten, nicht nur für ein passendes. Äquivalent:

f(n)=o(g(n))  ⟺  lim⁡n→∞f(n)g(n)=0.f(n)=o(g(n)) \iff \lim_{n\to\infty}\frac{f(n)}{g(n)} = 0.

  • 3n=o(n2)3n=o(n^2), denn 3n/n2=3/n→03n/n^2 = 3/n\to0. ✔
  • n2/2−3n≠o(n2)n^2/2-3n\neq o(n^2), denn der Quotient geht gegen 12≠0\tfrac12\neq0.
  • 6n3≠o(n2)6n^3\neq o(n^2)

Small-omega: echt größer​

ω(g(n))={f(n):∀ c>0 ∃ n0>0 mit 0≤c ∣g(n)∣<∣f(n)∣  ∀n≥n0}\omega(g(n)) = \{f(n) : \forall\, c>0\ \exists\, n_0>0 \text{ mit } 0\le c\,\lvert g(n)\rvert < \lvert f(n)\rvert\ \ \forall n\ge n_0\}

f(n)=ω(g(n))  ⟺  lim⁡n→∞f(n)g(n)=∞.f(n)=\omega(g(n)) \iff \lim_{n\to\infty}\frac{f(n)}{g(n)} = \infty.

  • 3n≠ω(n2)3n\neq\omega(n^2)
  • n2−3n≠ω(n2)n^2-3n\neq\omega(n^2) (Quotient →1\to1)
  • 6n3=ω(n2)6n^3=\omega(n^2) (Quotient 6n→∞6n\to\infty) ✔

Überblick​

SymbolAnalogie3n3n vs. n2n^2n2/2−3nn^2/2-3n vs. n2n^26n36n^3 vs. n2n^2
OO≤\le✔✔✘
Ω\Omega≥\ge✘✔✔
Θ\Theta==✘✔✘
oo<<✔✘✘
ω\omega>>✘✘✔

Wachstumshierarchie (Ergänzung)​

1  <  log⁡n  <  n  <  n  <  nlog⁡n  <  n2  <  n3  <  2n  <  n!1 \;<\; \log n \;<\; \sqrt n \;<\; n \;<\; n\log n \;<\; n^2 \;<\; n^3 \;<\; 2^n \;<\; n!

(jeweils im Sinne von oo). Für die konvexe Hülle sind relevant: O(n3)O(n^3) naiv, O(n2)O(n^2) Jarvis im Worst Case, O(nlog⁡n)O(n\log n) Graham und O(nlog⁡h)O(n\log h) Chan.

Gefühl für die Größenordnungen bei n=106n=10^6 Punkten und 10910^9 Operationen pro Sekunde:

LaufzeitOperationenZeit
nlog⁡nn\log n2⋅1072\cdot10^70,02 s
n2n^2101210^{12}ca. 17 min
n3n^3101810^{18}ca. 32 Jahre