Datenstrukturen

Werbung
Datenstrukturen
Mariano Zelke
Sommersemester 2012
Laufzeitmessung
Für welchen Rechner (welche Hardware) sollen wir die Laufzeit
berechnen?
I
Analysiere die Laufzeit auf einem abstrakten Rechner:
I
I
I
I
Der Speicher besteht aus Registern, die eine ganze Zahl speichern
können.
Eine CPU führt einfache boolesche und arithmetische Operationen
aus.
Daten werden zwischen CPU und Speicher durch (indirekte) Ladeund Speicherbefehle ausgetauscht.
Damit ist die Laufzeitberechnung für unseren abstrakten Rechner
gültig, aber wir erhalten für einen speziellen Rechner nur eine bis
auf einen konstanten Faktor exakte Schätzung.
Also:
(Analysierte bzw. geschätzte Laufzeit) = ch ·(tatsächliche Laufzeit)
für einen konstanten Wert ch
Mariano Zelke
Datenstrukturen
2/17
Laufzeitmessung
Für welche Programmiersprache und welchen Compiler (welche
Software) sollen wir die Laufzeit berechnen?
I
Wir sollten“ mit einer Assemblersprache arbeiten: Wir sind vom
”
Compiler unabhängig und haben es mit einer geringen Anzahl
verschiedener Anweisungen zu tun.
I
Aber die Programmierung ist viel zu umständlich und wir wählen
deshalb C++ bzw. Pseudocode.
I
Wenn wir die Anzahl ausgeführter C++ Befehle zählen, erhalten wir
für die tatsächliche Anzahl ausgeführter Assembler Anweisungen nur
eine Schätzung, die bis auf einen konstanten Faktor exakt ist.
Also:
(Analysierte bzw. geschätzte Laufzeit) = cs ·(tatsächliche Laufzeit)
für einen konstanten Wert cs
Mariano Zelke
Datenstrukturen
3/17
Laufzeitmessung
Ziel für unsere Laufzeitanalyse kann nur sein, die Laufzeit so
abzuschätzen, dass gilt
(Analysierte bzw. geschätzte Laufzeit) = ch · cs · (tatsächliche Laufzeit),
wobei ch und cs Konstanten sind, die von der tatsächlichen Hard- und
Software abhängen.
Mariano Zelke
Datenstrukturen
4/17
Laufzeitmessung
Typischerweise hängt die Laufzeit eines Algorithmus von der Eingabe ab.
Für welche Eingabe sollen wir die Laufzeit berechnen?
I
I
Eine Laufzeitbestimmung für alle möglichen Eingaben ist sinnlos.
Betrachte stattdessen die worst-case Laufzeit eines Algorithmus
oder einer Datenstruktur für jede Eingabelänge.
I
I
Unsere Laufzeitbestimmung ist letztlich nur eine bis auf einen
konstanten Faktor exakte Schätzung.
Wir interessieren uns vor allen Dingen für die Laufzeit großer“
”
Eingaben und unterschlagen“ konstante Faktoren.
”
Wie verhält sich die Datenstruktur oder der Algorithmus unter
wachsender Eingabelänge?
Also:
Wir erhalten eine von der jeweiligen Rechnerumgebung unabhängige
Laufzeitanalyse, die das Wachstumsverhalten der tatsächlichen Laufzeit
verlässlich voraussagt.
Mariano Zelke
Datenstrukturen
5/17
Ein Beispiel: Das Teilfolgenproblem
I
Die Eingabe besteht aus n ganzen Zahlen a1 , . . . , an .
I
Definiere f (i, j) = ai + ai+1 + · · · + aj für 1 ≤ i ≤ j ≤ n.
I
Das Ziel ist die Berechnung von max{f (i, j)|1 ≤ i ≤ j ≤ n},
also die maximale Teilfolgensumme.
2, −3,
4, −1, −1,
4,
1, −2
Maximum der f (i, j): f (3, 7) = 7
Mariano Zelke
Datenstrukturen
6/17
Ein Beispiel: Das Teilfolgenproblem
I
Die Eingabe besteht aus n ganzen Zahlen a1 , . . . , an .
I
Definiere f (i, j) = ai + ai+1 + · · · + aj für 1 ≤ i ≤ j ≤ n.
I
Das Ziel ist die Berechnung von max{f (i, j)|1 ≤ i ≤ j ≤ n},
also die maximale Teilfolgensumme.
Wir betrachten nur Algorithmen A, die ausschließlich Additionen und
Vergleichsoperationen auf den Daten ausführen.
I
AdditionenA (n) =
maxa1 ,...an ,∈Z {Anzahl Additionen von A für Eingabe (a1 , . . . , an )}
I
VergleicheA (n) =
maxa1 ,...,an ∈Z {Anzahl Vergleiche von A für Eingabe (a1 , . . . , an )}.
I
ZeitA (n) = AdditionenA (n) + VergleicheA (n) ist die worst-case
Rechenzeit von Algorithmus A.
Mariano Zelke
Datenstrukturen
7/17
Das Teilfolgenproblem: Algorithmus A1
Max = −∞;
for (i=1 ; i <= n; i++)
for (j=i ; j <= n; j++){
Berechne f (i, j) mit j−i Additionen;
Max = max{f (i, j), Max}; }
Analysiere die geschachtelten For-Schleifen durch geschachtelte Summen:
Wir benötigen j − i Additionen zur Berechnung von f (i, j). Also ist
n X
n
X
AdditionenA1 (n) =
(j − i).
i=1 j=i
n
n P
P
Eine obere Schranke: AdditionenA1 (n) ≤
n = n3 .
i=1 j=1
n/4
n
P P
Eine untere Schranke: AdditionenA1 (n) ≥
i=1 j=3n/4+1
und damit folgt AdditionenA1 (n) ≥
Mariano Zelke
n
4
·
n
4
·
n
2
Datenstrukturen
=
n3
32
n
2
.
8/17
Die worst-case Laufzeit von A1
I
Wie viele Vergleiche werden für die n Zahlen a1 , . . . , an ausgeführt?
VergleicheA1 (n) =
n X
n
X
1=
i=1 j=i
n
X
(n − i + 1)
i=1
= n + (n − 1) + · · · + 1
n
X
n · (n + 1)
.
=
i=
2
i=1
I
Und die worst-case Laufzeit?
I
I
I
ZeitA1 (n) = AdditionenA1 (n) + VergleicheA1 (n).
n3
32
n3
32
≤ AdditionenA1 (n) ≤ n3 . Also ist
+
n·(n+1)
2
≤ ZeitA1 (n) ≤ n3 +
n·(n+1)
.
2
Wir möchten das wesentliche Ergebnis festhalten, nämlich, dass die
Laufzeit kubisch ist.
Mariano Zelke
Datenstrukturen
9/17
Vergleich von Laufzeiten
4·
n3
32
+
n(n+1)
2
n3
32
+
n(n+1)
2
≤ ZeitA1 (n)
2n = ZeitB (n)
n
0
Wir wollen ausdrücken, dass im Allgemeinen das Wachstum von ZeitB (n)
höchstens so schnell ist wie das Wachstum von ZeitA1 (n).
Aber es gilt nicht: ZeitB (n) ≤ ZeitA1 (n) für alle n ∈ N
Allerdings gilt: ZeitB (n) ≤ 4 · ZeitA1 (n) für alle n ∈ N
Mariano Zelke
Datenstrukturen
10/17
Vergleich von Laufzeiten
4·
n3
32
+
n(n+1)
2
n3
32
+
n(n+1)
2
≤ ZeitA1 (n)
2n = ZeitB (n)
n
0
Wir halten fest:
Es gibt Konstante c > 0, so dass ZeitB (n) ≤ c· ZeitA1 (n) für alle n ∈ N
Rechtfertigung für Skalierung mit c:
Laufzeiten sind sowieso nur Schätzungen bis auf konstanten Faktor.
Mariano Zelke
Datenstrukturen
10/17
Vergleich von Laufzeiten
n3
32
n2
3
+
n(n+1)
2
≤ ZeitA1 (n)
+ 3 = ZeitD (n)
n
0
n0
Wir wollen ausdrücken, dass im Allgemeinen das Wachstum von ZeitD (n)
höchstens so schnell ist wie das Wachstum von ZeitA1 (n).
Aber es gilt nicht: ZeitD (n) ≤ ZeitA1 (n) für alle n ∈ N
Allerdings gilt: ZeitD (n) ≤ ZeitA1 (n) für alle n ≥ n0
Mariano Zelke
Datenstrukturen
10/17
Vergleich von Laufzeiten
n3
32
n2
3
+
n(n+1)
2
≤ ZeitA1 (n)
+ 3 = ZeitD (n)
n
0
n0
Wir halten fest:
Es gibt n0 ∈ N, so dass ZeitD (n) ≤ ZeitA1 (n) für alle n ≥ n0
Rechtfertigung für Betrachtung erst ab n0 : Wir interessieren
uns für Wachstumsverhalten und damit nur für große“ Eingaben
”
Mariano Zelke
Datenstrukturen
10/17
Die asymptotische Notation
f , g : N → R≥0 seien Funktionen, die einer Eingabelänge n ∈ N eine
nicht-negative Laufzeit f (n), bzw. g (n) zuweisen.
I
Die Groß-Oh Notation: f = O(g ) ⇔ Es gibt eine positive Konstante
c > 0 und eine natürliche Zahl n0 ∈ N, so dass
f (n) ≤ c · g (n)
für alle n ≥ n0 gilt: f wächst höchstens so schnell wie g .
I
f = Ω(g ) ⇔ g = O(f ) : f wächst mindestens so schnell wie g .
I
f = Θ(g ) ⇔ f = O(g ) und g = O(f ) : f und g wachsen gleich
schnell.
I
I
= 0: f wächst
Die Klein-Oh Notation: f = o(g ) ⇔ lim gf (n)
n→∞ (n)
langsamer als g .
g (n)
n→∞ f (n)
f = ω(g ) ⇔ lim
Mariano Zelke
= 0: f wächst schneller als g .
Datenstrukturen
11/17
Die asymptotische Notation, Beispiel
4·
n3
32
+
n(n+1)
2
n3
32
+
n(n+1)
2
≤ ZeitA1 (n)
2n = ZeitB (n)
n
0 = n0
Es gilt: ZeitB (n) = O(ZeitA1 (n)) denn:
Es gibt positive Konstante c = 4 und n0 = 0 so dass
ZeitB (n) ≤ c · ZeitA1 (n) für alle n ≥ n0
Mariano Zelke
Datenstrukturen
12/17
Die asymptotische Notation, Beispiel
n3
32
n2
3
+
n(n+1)
2
≤ ZeitA1 (n)
+ 3 = ZeitD (n)
n
0
n0
Es gilt: ZeitD (n) = O(ZeitA1 (n)) denn:
Es gibt positive Konstante c = 1 und n0 = 2,62 so dass
ZeitD (n) ≤ c · ZeitA1 (n) für alle n ≥ n0
Mariano Zelke
Datenstrukturen
12/17
Die asymptotische Notation, Beispiel
3·
n3
32
+
n(n+1)
2
n3
32
n2
3
+
n(n+1)
2
≤ ZeitA1 (n)
+ 3 = ZeitD (n)
n
0
n0
Es gilt: ZeitD (n) = O(ZeitA1 (n)) denn:
Es gibt positive Konstante c = 3 und ein n0 = 1,5 so dass
ZeitD (n) ≤ c · ZeitA1 (n) für alle n ≥ n0
Mariano Zelke
Datenstrukturen
12/17
Die Laufzeit von A1 ist kubisch
Wir müssen ZeitA1 (n) = O(n3 ) und n3 = O(ZeitA1 (n)) zeigen.
I
I
Warum gilt ZeitA1 (n) = O(n3 )?
n·(n+1)
.
2
I
Wir wissen ZeitA1 (n) ≤ n3 +
I
Also ist ZeitA1 (n) ≤ n3 +
I
ZeitA1 (n) = O(n3 ): Setze c = 2 und n0 = 1.
n·2n
2
≤ n3 +
2n3
2
= 2 · n3 .
Warum gilt n3 = O(ZeitA1 (n))?
I
Wir wissen
3
n
32
n3
32
+
n·(n+1)
2
≤ ZeitA1 (n).
≤ ZeitA1 (n) und deshalb folgt n3 ≤ 32 · ZeitA1 (n).
I
Also ist
I
n3 = O(ZeitA1 (n)): Setze c = 32 und n0 = 0.
ZeitA1 (n) = Θ(n3 ): Die Laufzeit wächst (ungefähr) um den Faktor 8,
wenn wir die Eingabelänge verdoppeln.
Mariano Zelke
Datenstrukturen
13/17
Wie schnell dominiert die Asymptotik?
Annahme: Ein einfacher Befehl benötigt 10−9 Sekunden.
n2
n
n3
n10
2n
n!
1012
≥ 1013
≥ 1031
| {z }
16
32
256
1.024
4.096
32.768
≥
≥ 1015
65536
≥ 4 · 109
64
4.096
262.144
≥ 1018
| {z }
≥ 6 · 1019
| {z }
128
256
512
1024
106
16.384
65.536
262.144
1.048.576
≥ 1012
| {z }
mehr als
15 Minuten
2.097.152
16.777.216
134.217.728
≥ 109
≥ 1018
| {z }
mehr als
10 Jahre
mehr als
10 Jahre
mehr als
600 Jahre
Mariano Zelke
Datenstrukturen
mehr als
1014 Jahre
14/17
Grenzwerte
Grenzwerte sollten das Wachstum voraussagen!
Der Grenzwert der Folge
f (n)
g (n)
f (n)
n→∞ g (n)
existiere und es sei lim
= c.
I
Wenn c = 0, dann ist f = o(g ). (f wächst langsamer als g .)
I
Wenn 0 < c < ∞, dann ist f = Θ(g ).
(f und g wachsen gleich schnell.)
I
Wenn c = ∞, dann ist f = ω(g ). (f wächst schneller als g .)
I
Wenn 0 ≤ c < ∞, dann ist f = O(g ).
(f wächst höchstens so schnell wie g .)
I
Wenn 0 < c ≤ ∞, dann ist f = Ω(g ).
(f wächst mindestens so schnell wie g .)
Mariano Zelke
Datenstrukturen
15/17
Betrachtung von Grenzwerten, Beispiel
n3
32
+
n(n+1)
2
≤ ZeitA1 (n)
2n = ZeitB (n)
n
0
ZeitA1 (n)
lim
≥ lim
n→∞ ZeitB (n)
n→∞
n3
32
+ n(n+1)
2
= lim
n→∞
2n
n3
n(n + 1)
+
64n
4n
=∞
Damit gilt: ZeitA1 (n) = ω(ZeitB (n))
Das heißt, ZeitA1 (n) wächst schneller als ZeitB (n).
Mariano Zelke
Datenstrukturen
16/17
Betrachtung von Grenzwerten, Beispiel
n3
32
n2
3
+
n(n+1)
2
≤ ZeitA1 (n)
+ 3 = ZeitD (n)
n
0
ZeitD (n)
lim
≤ lim
n→∞ ZeitA1 (n)
n→∞
n3
32
n2
3
+3
+
n(n+1)
2
32n2 + 288
= 0
n→∞ 3n3 + 48n(n + 1)
= lim
Damit gilt: ZeitD (n) = o(ZeitA1 (n))
Das heißt, ZeitD (n) wächst langsamer als ZeitA1 (n).
Mariano Zelke
Datenstrukturen
16/17
Rechnen mit Grenzwerten
f , g : N → R≥0 seien Funktionen.
(a) Die Operation ◦ bezeichne eine der Operationen +, − oder ∗.
Dann gilt
lim (f (n) ◦ g (n)) = lim f (n) ◦ lim g (n),
n→∞
n→∞
n→∞
falls die beiden Grenzwerte auf der rechten Seite existieren und
endlich sind.
f (n)
n→∞ g (n)
(b) lim
lim f (n)
=
n→∞
lim g (n) ,
falls die beiden Grenzwerte auf der rechten
n→∞
Seite existieren, endlich sind und lim g (n) 6= 0 gilt.
n→∞
I
I
lim
n→∞
n3 +n·(n+1)/2
n3
Also ist n3 +
Mariano Zelke
n3
3
n→∞ n
= lim
n·(n+1)
2
+ lim
n→∞
n·(n+1)/2
n3
= 1.
= Θ(n3 ).
Datenstrukturen
17/17
Herunterladen