Skript in PDF - Theoretische Informatik - Technische Universität ...
Skript in PDF - Theoretische Informatik - Technische Universität ... Skript in PDF - Theoretische Informatik - Technische Universität ...
132 KAPITEL 6. KOMPLEXITÄT VON ALGORITHMEN zifikation realisierbar ist. Trotz einigen Wochen intensiven Versuchens ist es Ihnen nicht gelungen, das Programm zu schreiben. Was jetzt? Wenn Sie die Produktspezifikation analysieren und feststellen, dass sie sehr allgemein formuliert ist, liegt es vielleicht an der Allgemeinheit und nicht an Ihrer Unfähigkeit. Es wäre z.B. toll, wenn Sie zeigen können, dass das von Ihnen verlangte Programm eigentlich auch das Halteproblem lösen könnte – dann können Sie Ihrem Chef beweisen, dass er unlösbare Aufgaben erteilt. Das ist aber leider nicht sehr wahrscheinlich, denn das Halteproblem ist doch sehr allgemein. Also versuchen Sie zu zeigen, dass Ihr Programm eines von den hunderten N P-vollständiger Problemen lösen würde – das zeigt nicht, dass die Aufgabe prinzipiell nicht effektiv implementierbar wäre, aber dass es schon einer Schar ausgezeichneter Programmierer nicht gelungen ist, einen effizienten Algorithmus zu entwickeln. 6.1 Beispiele effizienter Algorithmen In diesem Abschnitt illustrieren wir eine genaue Analyse der Effizienz von Algorithmen an einigen wichtigen Beispielen von Graphen-Algorithmen. Ein gerichteter Graph G = (V, E), wobei V die Menge aller (n) Knoten und E die Menge aller Kanten (d.h. geordneten Paaren von Knoten) ist, wird gewöhnlich durch seine n × n-Adjazenzmatrix repräsentiert, wobei aij = (aij) 1 falls (i, j) eine Kante in E ist 0 sonst Oder durch Adjazenzlisten, d.h., durch n lineare Listen, wobei die i-te Liste alle Knoten j mit (i, j) ∈ E enthält und die heads (Listenköpfe) in einem Array gespeichert werden. Beispiel: für den gerichteten Graphen 1 5 2 3 4 haben wir die Adjazenzmatrix der Gesamtgröße m = n 2 ⎛ 0 ⎜ ⎜0 ⎜ ⎜0 ⎝0 1 0 1 1 0 0 0 1 ⎞ 0 0 1 0 ⎟ 0 0 ⎟ 0 1⎠ 1 0 0 0 0 und die Adjazenzlisten der Gesamtgröße m = n + k
6.1. BEISPIELE EFFIZIENTER ALGORITHMEN 133 1 2 2 2 4 3 3 4 5 3 5 1 Beispiel 1 (Topologisches Sortieren). In Abschnitt 2.7 haben wir den folgenden Algorithmus für das topologische Sortieren eines gerichteten Graphen G = (V, E) beschrieben: 1: {(1) Initialisierung} 2: i := 0 3: W := V {W – die Menge der noch nicht bearbeiteten Knoten} 4: {(2) Rekursionsschritt} 5: while ein Knoten x ∈ W ohne Vorgänger existiert do 6: i := i + 1; 7: ord(x) = i; 8: W := W − {x} 9: Löschen des Knotens x aus dem Graphen 10: od Wie lange dauert dieser Algorithmus für einen Graphen mit n Knoten? Nehmen wir an, dass eine Eintragung in die Liste ord sowie die Modifikation der Variablen i und W eine konstante Zahl A von Zeiteinheiten dauert. Um einen Knoten x ohne Vorgänger zu finden, suchen wir in der Adjazenzmatrix eine Spalte mit lauter Nullen; das dauert Km 2 Zeiteinheiten, wobei K eine Konstante ist und m die aktuelle Knotenzahl ( m = n, n − 1, . . .,1), und die Entfernung eines Knotens dauert eine konstante Zahl L von Zeiteinheiten. Dann ist die gesamte Zahl von Zeiteinheiten für diesen Algorithmus T = 2A + n m=1 (Km 2 + 3A + L) > Cn 3 für eine Konstante C. Dieser Algorithmus kann viel effizienter implementiert werden. Diesmal stellen wir den Graphen mittels Adjazenzlisten dar. Wir bezeichnen für jeden Knoten v mit IN[v] (ein Array, v = 1, . . .,n) die Zahl aller Kanten mit dem Endknoten v und wir setzen U = {v; v ∈ V und IN[v] = 0}. Algorithmus für Topologisches Sortieren Eingabe: Gerichteter Graph G = (V, E) mit n Knoten und k Kanten Ausgabe: Topologische Sortierung ord : V → {1, . . .,n} von G, falls G azyklisch ist 1: {(1) Initialisierung} 2: i := 0 {i – die letzte Zahl, die ord benutzt hat} 3: U := ∅ {U - die Menge aller Knoten v mit IN[v] = 0} 4: IN[1] := 0, . . .,IN[n] := 0
- Seite 16 und 17: 82 KAPITEL 3. TURINGMASCHINEN 3.2.5
- Seite 18 und 19: 84 KAPITEL 3. TURINGMASCHINEN (q0,
- Seite 20 und 21: 86 KAPITEL 3. TURINGMASCHINEN 3. Di
- Seite 22 und 23: 88 KAPITEL 3. TURINGMASCHINEN 4. L
- Seite 24 und 25: 90 KAPITEL 3. TURINGMASCHINEN 3.4 N
- Seite 26 und 27: 92 KAPITEL 3. TURINGMASCHINEN 1. Di
- Seite 28 und 29: 94 KAPITEL 3. TURINGMASCHINEN sie k
- Seite 30 und 31: 96 KAPITEL 3. TURINGMASCHINEN falls
- Seite 32 und 33: 98 KAPITEL 4. CHURCHSCHE THESE Zeil
- Seite 34 und 35: 100 KAPITEL 4. CHURCHSCHE THESE 0.
- Seite 36 und 37: 102 KAPITEL 4. CHURCHSCHE THESE 4.2
- Seite 38 und 39: 104 KAPITEL 4. CHURCHSCHE THESE Bei
- Seite 40 und 41: 106 KAPITEL 4. CHURCHSCHE THESE [uq
- Seite 42 und 43: 108 KAPITEL 4. CHURCHSCHE THESE Bew
- Seite 44 und 45: 110 KAPITEL 4. CHURCHSCHE THESE Alg
- Seite 46 und 47: 112 KAPITEL 4. CHURCHSCHE THESE All
- Seite 48 und 49: 114 KAPITEL 4. CHURCHSCHE THESE Bem
- Seite 50 und 51: 116 KAPITEL 4. CHURCHSCHE THESE Sei
- Seite 52 und 53: 118 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 54 und 55: 120 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 56 und 57: 122 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 58 und 59: 124 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 60 und 61: 126 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 62 und 63: 128 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 64 und 65: 130 KAPITEL 5. UNENTSCHEIDBARE PROB
- Seite 68 und 69: 134 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 70 und 71: 136 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 72 und 73: 138 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 74 und 75: 140 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 76 und 77: 142 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 78 und 79: 144 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 80 und 81: 146 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 82 und 83: 148 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 84 und 85: 150 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 86 und 87: 152 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 88 und 89: 154 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 90 und 91: 156 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 92 und 93: 158 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 94 und 95: 160 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 96 und 97: 162 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 98 und 99: 164 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 100 und 101: 166 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 102 und 103: 168 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 104 und 105: 170 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 106 und 107: 172 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 108 und 109: 174 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 110 und 111: 176 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 112 und 113: 178 KAPITEL 6. KOMPLEXITÄT VON ALG
- Seite 114 und 115: 180 KAPITEL 6. KOMPLEXITÄT VON ALG
6.1. BEISPIELE EFFIZIENTER ALGORITHMEN 133<br />
1 <br />
2<br />
2 <br />
2 <br />
4 <br />
3<br />
3<br />
4 <br />
5 <br />
3<br />
5 <br />
1<br />
<br />
<br />
<br />
Beispiel 1 (Topologisches Sortieren). In Abschnitt 2.7 haben wir den folgenden<br />
Algorithmus für das topologische Sortieren e<strong>in</strong>es gerichteten Graphen G = (V, E)<br />
beschrieben:<br />
1: {(1) Initialisierung}<br />
2: i := 0<br />
3: W := V {W – die Menge der noch nicht bearbeiteten Knoten}<br />
4: {(2) Rekursionsschritt}<br />
5: while e<strong>in</strong> Knoten x ∈ W ohne Vorgänger existiert do<br />
6: i := i + 1;<br />
7: ord(x) = i;<br />
8: W := W − {x}<br />
9: Löschen des Knotens x aus dem Graphen<br />
10: od<br />
Wie lange dauert dieser Algorithmus für e<strong>in</strong>en Graphen mit n Knoten? Nehmen<br />
wir an, dass e<strong>in</strong>e E<strong>in</strong>tragung <strong>in</strong> die Liste ord sowie die Modifikation der Variablen<br />
i und W e<strong>in</strong>e konstante Zahl A von Zeite<strong>in</strong>heiten dauert. Um e<strong>in</strong>en Knoten x ohne<br />
Vorgänger zu f<strong>in</strong>den, suchen wir <strong>in</strong> der Adjazenzmatrix e<strong>in</strong>e Spalte mit lauter Nullen;<br />
das dauert Km 2 Zeite<strong>in</strong>heiten, wobei K e<strong>in</strong>e Konstante ist und m die aktuelle<br />
Knotenzahl ( m = n, n − 1, . . .,1), und die Entfernung e<strong>in</strong>es Knotens dauert e<strong>in</strong>e<br />
konstante Zahl L von Zeite<strong>in</strong>heiten. Dann ist die gesamte Zahl von Zeite<strong>in</strong>heiten<br />
für diesen Algorithmus<br />
T = 2A +<br />
n<br />
m=1<br />
(Km 2 + 3A + L) > Cn 3<br />
<br />
für e<strong>in</strong>e Konstante C.<br />
Dieser Algorithmus kann viel effizienter implementiert werden. Diesmal stellen wir<br />
den Graphen mittels Adjazenzlisten dar. Wir bezeichnen für jeden Knoten v mit<br />
IN[v] (e<strong>in</strong> Array, v = 1, . . .,n)<br />
die Zahl aller Kanten mit dem Endknoten v und wir setzen<br />
U = {v; v ∈ V und IN[v] = 0}.<br />
Algorithmus für Topologisches Sortieren<br />
E<strong>in</strong>gabe: Gerichteter Graph G = (V, E) mit n Knoten und k Kanten<br />
Ausgabe: Topologische Sortierung ord : V → {1, . . .,n} von G, falls G azyklisch<br />
ist<br />
1: {(1) Initialisierung}<br />
2: i := 0 {i – die letzte Zahl, die ord benutzt hat}<br />
3: U := ∅ {U - die Menge aller Knoten v mit IN[v] = 0}<br />
4: IN[1] := 0, . . .,IN[n] := 0