1.2.4 Laufzeit & 1.2.5 O-Kalkül
1.2.4 Laufzeit von Algorithmen
Laufzeit eines Algorithmus = Anzahl der ausgeführten primitiven Operationen. Eine primitive Operation entspricht einem Zeitschritt.
Die Laufzeit hängt von der Eingabegröße n n n ab (z.B. Anzahl der Punkte). Sie ist also eine Funktion von n n n , die Laufzeitfunktion T ( n ) T(n) T ( n ) , etwa
T ( n ) = a n 2 + b n + c f u ¨ r Konstanten a , b , c . T(n) = a n^2 + bn + c\qquad\text{für Konstanten } a,b,c. T ( n ) = a n 2 + bn + c f u ¨ r Konstanten a , b , c .
Best, Worst, Average Case
Bei gleicher Eingabegröße kann die Laufzeit je nach konkreter Eingabe unterschiedlich sein:
Analyse Frage Beispiel Jarvis' March (§2.5) Best Case schnellste Eingabe der Größe n n n ? Hülle ist ein Dreieck: O ( n ) O(n) O ( n ) Worst Case langsamste Eingabe der Größe n n n ? alle Punkte auf der Hülle: O ( n 2 ) O(n^2) O ( n 2 ) Average Case Erwartungswert über eine Verteilung der Eingaben? gleichverteilte Punkte im Quadrat: O ( n log n ) O(n\log 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 ) = a n 2 + b n + c T(n)=an^2+bn+c T ( n ) = a n 2 + bn + c hat die Ordnung n 2 n^2 n 2 .
T ( n ) = a n + b T(n)=an+b T ( n ) = an + b hat die Ordnung n n n .
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) f ( n ) und g ( n ) g(n) g ( n ) für große n n n ? „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 , n 0 > 0 mit 0 ≤ ∣ f ( n ) ∣ ≤ c ∣ g ( n ) ∣ ∀ n ≥ n 0 } 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\} O ( g ( n )) = { f ( n ) : ∃ c > 0 , n 0 > 0 mit 0 ≤ ∣ f ( n )∣ ≤ c ∣ g ( n )∣ ∀ n ≥ n 0 }
In Worten: f f f wächst höchstens so schnell wie g g g . Ab einer Stelle n 0 n_0 n 0 liegt f f f immer unter einem festen Vielfachen von g g g .
Schreibweise: f ( n ) = O ( g ( n ) ) f(n)=O(g(n)) f ( n ) = O ( g ( n )) statt f ( n ) ∈ O ( g ( n ) ) f(n)\in O(g(n)) f ( n ) ∈ O ( g ( n )) . Das „=“ ist nur in dieser Richtung zu lesen, O ( n 2 ) = 3 n O(n^2)=3n O ( n 2 ) = 3 n ergibt keinen Sinn.
Beispiele mit Nachweis:
3 n = O ( n 2 ) 3n=O(n^2) 3 n = O ( n 2 ) : wähle c = 3 c=3 c = 3 , n 0 = 1 n_0=1 n 0 = 1 , denn 3 n ≤ 3 n 2 3n\le 3n^2 3 n ≤ 3 n 2 für n ≥ 1 n\ge1 n ≥ 1 . ✔
n 2 / 2 − 3 n = O ( n 2 ) n^2/2-3n = O(n^2) n 2 /2 − 3 n = O ( n 2 ) : wähle c = 1 2 c=\tfrac12 c = 2 1 , n 0 = 6 n_0=6 n 0 = 6 (ab da ist n 2 / 2 − 3 n ≥ 0 n^2/2-3n\ge 0 n 2 /2 − 3 n ≥ 0 und ≤ n 2 / 2 \le n^2/2 ≤ n 2 /2 ). ✔
6 n 3 ≠ O ( n 2 ) 6n^3\neq O(n^2) 6 n 3 = O ( n 2 ) : 6 n 3 ≤ c n 2 ⟺ n ≤ c / 6 6n^3\le cn^2 \iff n\le c/6 6 n 3 ≤ c n 2 ⟺ n ≤ c /6 gilt für kein festes c c c für alle großen n n n . ✘
Zum Ausprobieren: Wähle f f f und verändere c c c . Grün markiert ist der Bereich ab n 0 n_0 n 0 , in dem die Ungleichung gilt. Bei 6 n 3 6n^3 6 n 3 findet man für O ( n 2 ) O(n^2) O ( n 2 ) kein c c c , das bis zum rechten Rand hält – schieb n n n hoch und es kippt wieder.
Big-Omega: untere Schranke (≥)
Ω ( g ( n ) ) = { f ( n ) : ∃ c > 0 , n 0 > 0 mit 0 ≤ c ∣ g ( n ) ∣ ≤ ∣ f ( n ) ∣ ∀ n ≥ n 0 } \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\} Ω ( g ( n )) = { f ( n ) : ∃ c > 0 , n 0 > 0 mit 0 ≤ c ∣ g ( n )∣ ≤ ∣ f ( n )∣ ∀ n ≥ n 0 }
f f f wächst mindestens so schnell wie g g g .
3 n ≠ Ω ( n 2 ) 3n\neq\Omega(n^2) 3 n = Ω ( n 2 )
n 2 / 2 − 3 n = Ω ( n 2 ) n^2/2-3n=\Omega(n^2) n 2 /2 − 3 n = Ω ( n 2 ) : wähle c = 1 4 c=\tfrac14 c = 4 1 , n 0 = 12 n_0=12 n 0 = 12 (dann n 2 / 2 − 3 n ≥ n 2 / 4 ⟺ n ≥ 12 n^2/2-3n\ge n^2/4 \iff n\ge 12 n 2 /2 − 3 n ≥ n 2 /4 ⟺ n ≥ 12 ). ✔
6 n 3 = Ω ( n 2 ) 6n^3=\Omega(n^2) 6 n 3 = Ω ( n 2 )
Typische Verwendung: untere Schranken für Probleme : „Jeder Algorithmus braucht mindestens Ω ( n log n ) \Omega(n\log n) Ω ( n log n ) “, siehe 2.3 .
Big-Theta: exakte Ordnung (=)
Θ ( g ( n ) ) = { f ( n ) : ∃ c 1 , c 2 > 0 , n 0 > 0 mit 0 ≤ c 1 ∣ g ( n ) ∣ ≤ ∣ f ( n ) ∣ ≤ c 2 ∣ g ( n ) ∣ ∀ n ≥ n 0 } \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\} Θ ( g ( n )) = { f ( n ) : ∃ c 1 , c 2 > 0 , n 0 > 0 mit 0 ≤ c 1 ∣ g ( n )∣ ≤ ∣ f ( n )∣ ≤ c 2 ∣ g ( n )∣ ∀ n ≥ n 0 }
f f f wächst genauso schnell wie g g g : eingeklemmt zwischen zwei Vielfachen von g g g . Äquivalent: f = O ( g ) f=O(g) f = O ( g ) und f = Ω ( g ) f=\Omega(g) f = Ω ( g ) .
3 n ≠ Θ ( n 2 ) 3n\neq\Theta(n^2) 3 n = Θ ( n 2 )
n 2 / 2 − 3 n = Θ ( n 2 ) n^2/2-3n=\Theta(n^2) n 2 /2 − 3 n = Θ ( n 2 ) ✔
6 n 3 ≠ Θ ( n 2 ) 6n^3\neq\Theta(n^2) 6 n 3 = Θ ( n 2 )
Small-o: echt kleiner
o ( g ( n ) ) = { f ( n ) : ∀ c > 0 ∃ n 0 > 0 mit 0 ≤ ∣ f ( n ) ∣ < c ∣ g ( n ) ∣ ∀ n ≥ n 0 } 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\} o ( g ( n )) = { f ( n ) : ∀ c > 0 ∃ n 0 > 0 mit 0 ≤ ∣ f ( n )∣ < c ∣ g ( n )∣ ∀ n ≥ n 0 }
Unterschied zu O O O : Die Ungleichung muss für jedes noch so kleine c c c 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. f ( n ) = o ( g ( n )) ⟺ lim n → ∞ g ( n ) f ( n ) = 0.
3 n = o ( n 2 ) 3n=o(n^2) 3 n = o ( n 2 ) , denn 3 n / n 2 = 3 / n → 0 3n/n^2 = 3/n\to0 3 n / n 2 = 3/ n → 0 . ✔
n 2 / 2 − 3 n ≠ o ( n 2 ) n^2/2-3n\neq o(n^2) n 2 /2 − 3 n = o ( n 2 ) , denn der Quotient geht gegen 1 2 ≠ 0 \tfrac12\neq0 2 1 = 0 .
6 n 3 ≠ o ( n 2 ) 6n^3\neq o(n^2) 6 n 3 = o ( n 2 )
Small-omega: echt größer
ω ( g ( n ) ) = { f ( n ) : ∀ c > 0 ∃ n 0 > 0 mit 0 ≤ c ∣ g ( n ) ∣ < ∣ f ( n ) ∣ ∀ n ≥ n 0 } \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\} ω ( g ( n )) = { f ( n ) : ∀ c > 0 ∃ n 0 > 0 mit 0 ≤ c ∣ g ( n )∣ < ∣ f ( n )∣ ∀ n ≥ 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. f ( n ) = ω ( g ( n )) ⟺ lim n → ∞ g ( n ) f ( n ) = ∞.
3 n ≠ ω ( n 2 ) 3n\neq\omega(n^2) 3 n = ω ( n 2 )
n 2 − 3 n ≠ ω ( n 2 ) n^2-3n\neq\omega(n^2) n 2 − 3 n = ω ( n 2 ) (Quotient → 1 \to1 → 1 )
6 n 3 = ω ( n 2 ) 6n^3=\omega(n^2) 6 n 3 = ω ( n 2 ) (Quotient 6 n → ∞ 6n\to\infty 6 n → ∞ ) ✔
Überblick
Symbol Analogie 3 n 3n 3 n vs. n 2 n^2 n 2 n 2 / 2 − 3 n n^2/2-3n n 2 /2 − 3 n vs. n 2 n^2 n 2 6 n 3 6n^3 6 n 3 vs. n 2 n^2 n 2 O O O ≤ \le ≤ ✔ ✔ ✘ Ω \Omega Ω ≥ \ge ≥ ✘ ✔ ✔ Θ \Theta Θ = = = ✘ ✔ ✘ o o o < < < ✔ ✘ ✘ ω \omega ω > > > ✘ ✘ ✔
Wachstumshierarchie (Ergänzung)
1 < log n < n < n < n log n < n 2 < n 3 < 2 n < n ! 1 \;<\; \log n \;<\; \sqrt n \;<\; n \;<\; n\log n \;<\; n^2 \;<\; n^3 \;<\; 2^n \;<\; n! 1 < log n < n < n < n log n < n 2 < n 3 < 2 n < n !
(jeweils im Sinne von o o o ). Für die konvexe Hülle sind relevant: O ( n 3 ) O(n^3) O ( n 3 ) naiv, O ( n 2 ) O(n^2) O ( n 2 ) Jarvis im Worst Case, O ( n log n ) O(n\log n) O ( n log n ) Graham und O ( n log h ) O(n\log h) O ( n log h ) Chan.
Gefühl für die Größenordnungen bei n = 10 6 n=10^6 n = 1 0 6 Punkten und 10 9 10^9 1 0 9 Operationen pro Sekunde:
Laufzeit Operationen Zeit n log n n\log n n log n 2 ⋅ 10 7 2\cdot10^7 2 ⋅ 1 0 7 0,02 s n 2 n^2 n 2 10 12 10^{12} 1 0 12 ca. 17 min n 3 n^3 n 3 10 18 10^{18} 1 0 18 ca. 32 Jahre