Skript in PDF - Theoretische Informatik - Technische Universität ...

Skript in PDF - Theoretische Informatik - Technische Universität ... Skript in PDF - Theoretische Informatik - Technische Universität ...

iti.cs.tu.bs.de
von iti.cs.tu.bs.de Mehr von diesem Publisher
18.09.2013 Aufrufe

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

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

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!