Algorithmen und Datenstrukturen (für ET/IT) Wintersemester 2012/13 Dr. Tobias Lasser Computer Aided Medical Procedures Technische Universität München Wiederholung Graph-Algorithmen Algorithmus DFS Input: Graph G = (V , E ) Output: Vorgänger-Liste pred, Markierungen d, f DFS(G ): for each (Knoten v 2 V ) { farbe[v ] = weiss; pred[v ] = NULL; } zeit = 0; for each (Knoten v 2 V ) { if (farbe[v ] == weiss) DFSvisit(v ); } DFSvisit(v ): farbe[v ] = grau; // v war weiss zeit = zeit + 1; d[v ] = zeit; for each (Knoten u 2 adj[v ]) { if (farbe[u] == weiss) { pred[u] = v; DFSvisit(u); } } farbe[v ] = schwarz; // v ist fertig zeit = zeit + 1; f[v ] = zeit; 12 2 Wiederholung Graph-Algorithmen DFS: Beispiel-Ablauf 2 u v w u 1/_ Algorithmus DFSx u v 1/_ w u 2/_ v 1/_ w 2/_ 3/_ y z x y z x y v w u v w u v 2/_ Input: Graph G = (V , 1/_ E) Output: Vorgänger-Liste pred, Markierungen4/_d, f 3/_ x y DFS(G ): for each (Knoten uv 2 V )v { 2/_ farbe[v ] = weiss; 1/_ pred[v ] = NULL; B } 4/5 3/6 x y zeit = 0; for each (Knoten v 2 V ) { if (farbe[v ] == weiss) DFSvisit(v ); } z w z 1/_ 1/_ DFSvisit(v ): 2/_ B farbe[v ] = grau; // v war weiss B zeit =4/_zeit +3/_ 1; 4/5 x y z x d[v ] = zeit; for ueach (Knoten v w u 2 adj[v ]) u { 1/_ 2/7 == weiss) { 1/_ if (farbe[u] B B pred[u] = v; F DFSvisit(u); 4/5 3/6 4/5 x y z x } } farbe[v ] = schwarz; // v ist fertig zeit = zeit + 1; f[v ] = zeit; z w 2/_ 3/_ y z v w 2/7 3/6 y z 14 12 2 Wiederholung Graph-Algorithmen Algorithmus BFS Input: Graph G = (V , E ), Startknoten s 2 V Output: Vorgänger-Liste pred, Markierung d BFS(G , s): for each (Knoten v 2 V ) { // Initialisierung farbe[v ] = weiss; pred[v ] = NULL; d[v ] = 1; DFS: Beispiel-Ablauf 2 } farbe[s] = grau; d[s] = 0; Q = initialize(); Q.enqueue(s); u v w u v w u v w while ( 1/_ !Q.isEmpty() ){ 1/_ 2/_ 1/_ 2/_ u = Q.dequeue(); for each (v 2 adj[u]) { // besuche alle Nachbarn 3/_ Algorithmus DFSx ifx (farbe[v ] == zweiss) { x y z y y z farbe[v ] = grau; d[v ] = d[u] + 1; pred[v ] = u; );w u v w u Q.enqueue(v v u v w 2/_ 1/_ 2/_ } 1/_ ): 2/_ Input: Graph G = (V , 1/_ E) DFSvisit(v B } Output: Vorgänger-Liste pred, farbe[v ]= grau; // v war weiss B farbe[u] = schwarz; // u ist erledigt Markierungen4/_d, f 3/_ zeit =4/_zeit +3/_ 1; 4/5 3/_ } x y z x y z x y z DFS(G ): for each (Knoten uv 2 V )v { 2/_ farbe[v ] = weiss; 1/_ pred[v ] = NULL; B } 4/5 3/6 x y zeit = 0; for each (Knoten v 2 V ) { if (farbe[v ] == weiss) DFSvisit(v ); } w z d[v ] = zeit; for ueach (Knoten v w u 2 adj[v ]) u { 1/_ 2/7 == weiss) { 1/_ if (farbe[u] B B pred[u] = v; F DFSvisit(u); 4/5 3/6 4/5 x y z x } } farbe[v ] = schwarz; // v ist fertig zeit = zeit + 1; f[v ] = zeit; v w 24 2/7 3/6 y z 14 12 2 Wiederholung Graph-Algorithmen Algorithmus BFS Input: Graph G = (V , E ), Startknoten s 2 V Output: Vorgänger-Liste pred, Markierung d BFS(G , s): for each (Knoten v 2 V ) { // Initialisierung farbe[v ] = weiss; pred[v ] = NULL; d[v ] = 1; DFS: Beispiel-Ablauf 2 BFS: Beispiel-Ablauf 2 } farbe[s] = grau; d[s] = 0; Q = initialize(); Q.enqueue(s); u v w u v w u v w while ( 1/_ !Q.isEmpty() 1/_ 1/_ 2/_ r2/_ s) { t u r ∞ 0 ∞ ∞ u = Q.dequeue(); Q: Nachbarn s for each (v 2 adj[u]) { // besuche alle Algorithmus DFSx ifx (farbe[v ] == weiss) { ∞ x ∞ y 3/_ ∞ y z y z ∞ z w farbe[v ]v = grau; d[v ]x = d[u]y + 1; pred[v ] = u; v );w u v w u Q.enqueue(v v u v w r s t u r 2/_ 1/_ ∞ 2/_ } 1/_ ): 2/_1 0 2 Input: Graph G = (V , 1/_ E) DFSvisit(v B } Output: Vorgänger-Liste pred, farbe[v ]= grau; // v war weiss B Q: r t x farbe[u] = schwarz; u ist2 erledigt 1 Markierungen4/_d, f 3/_ zeit =4/_zeit +v3/_∞1; w // 4/5 ∞ 3/_ x v } x y z x y z x y y z DFS(G ): for each (Knoten uv 2 V )v { 2/_ farbe[v ] = weiss; 1/_ pred[v ] = NULL; B } 4/5 3/6 x y zeit = 0; for each (Knoten v 2 V ) { if (farbe[v ] == weiss) DFSvisit(v ); } w z d[v ] = zeit; t for ueach (Knoten ]) v r wsu 2 adj[v u u{ 1 0 2 3 1/_ 2/7 == weiss) { 1/_ if (farbe[u] B B pred[u] = v; F 2 1 2 ∞ v w x y DFSvisit(u); 4/5 3/6 4/5 x y z x } } farbe[v ] = schwarz; // v ist fertig zeit = zeit + 1; f[v ] = zeit; v Q: v u ∞ ∞ 1 ∞ w x s 1 2 2 v u 2 1 w 2 x Q: t x v Q: v u y ∞ y t 0 r ∞ 2 x s 1 w u 2 1 w Q: ∞ y t 0 ∞ 243 u 3/6 y t 0 r w 2/7 x s 1 3 y z 14 26 12 2 Programm heute 7 Fortgeschrittene Datenstrukturen 8 Such-Algorithmen 9 Graph-Algorithmen Tiefensuche Breitensuche Kürzeste Pfade Minimaler Spannbaum 10 Numerische Algorithmen Matrizen 3 Wiederholung Kürzeste Pfade Beispiel: kürzeste Pfade Navigationssystem: HH • Knoten sind Großstädte • Kanten sind Autobahnverbindung 200 450 DD 200 300 F 200 Fragestellungen: anderen Städten? 200 350 K Entfernungen in Kilometern • alle kürzesten Verbindungen von M zu B H • Gewichte der Kanten sind (grobe) • kürzester Weg von M nach HH? 200 250 300 300 150 KA N 50 S 250 150 M • alle kürzesten Verbindungen zwischen allen Städten? 33 4 Wiederholung Kürzeste Pfade Kürzeste Pfade: Algorithmen Sei G = (V , E ) gewichteter, gerichteter Graph. • Kürzeste Pfade in Graphen von fixem Startknoten s: • Dijkstra-Algorithmus (nur positive Kantengewichte) Beispiel: kürzeste PfadeGreedy-Algorithmus Komplexität: O(|E | log |V |) Navigationssystem: • A*-Algorithmus (nur positive Kantengewichte) Komplexität: mit guter Heuristik, besser als Dijkstra HH 200 Gewichte) • Knoten sind Großstädte• Bellman-Ford-Algorithmus (auch negative B 250 300 Komplexität: O(|V | ⇤ |E |) H • Kanten sind Autobahnverbindung 200 350 450 Knotenpaaren: • Kürzeste • Gewichte der Kanten Pfade in Graphen 200 zwischen allen sind (grobe) K DD • Floyd-Warshall-Algorithmus (all pairs shortest path) Entfernungen in Kilometern 200 F 300 basiert auf dynamischer Programmierung 200 300 150 Fragestellungen: Komplexität: ⇥(|V |3 ) N 50 KA • kürzester Weg von M nach HH? S • alle kürzesten Verbindungen von M zu anderen Städten? 250 150 M 34 • alle kürzesten Verbindungen zwischen allen Städten? 33 4 Wiederholung Kürzeste Pfade Beispiel: Ablauf Dijkstra-Algorithmus 1 u v 1 ∞ u ∞ 2 3 0 s 5 6 ∞ 5 y (x, 5) (u, 10) (v, ∞) • Dijkstra-Algorithmusu(nur positivev Kantengewichte) 1 8 2 3 s 5 6 0 (nur positive Kantengewichte) • A*-Algorithmus Q: (y, 7) (u, 8) (auch 2 2 3 0 7 Komplexität: mit5guter Heuristik, besser als Dijkstra HH 200 Komplexität: O(|V | ⇤ |E |) • Kanten sind Autobahnverbindung 1 8 v 13 10 Komplexität: O(|E | log |V |) 5 Bellman-Ford-Algorithmus x 300 y (y, ∞) u ∞ 10 ∞ 2 x Q: Q: (s,0) (u, ∞) (v, ∞) (x, ∞) Graph. (y, ∞) Sei G = (V , E ) gewichteter, gerichteter • Kürzeste Pfade in Graphen von fixem Startknoten s: Beispiel: kürzeste PfadeGreedy-Algorithmus 5 6 7 5 2 x • Knoten sind Großstädte• ∞ 2 3 0 7 5 Kürzeste Pfade: Algorithmen ∞ Navigationssystem: v 10 s s 1 10 10 H 200 (v, ∞) Q: 7 5 7 negative Gewichte) B 250 y 5 6 5 x 2 7 y (u, 8) (v, 13) 450 Knotenpaaren: • Kürzeste • Gewichte der Kanten Pfade in Graphen 200 zwischen allen sind (grobe) K DD • Floyd-Warshall-Algorithmus (all pairs shortest path) Entfernungen in Kilometern 200 F 300 basiert auf dynamischer Programmierung 200 300 150 Fragestellungen: Komplexität: ⇥(|V |3 ) N 50 KA • kürzester Weg von M nach HH? 350 S • alle kürzesten Verbindungen von M zu anderen Städten? 250 44 150 M 34 • alle kürzesten Verbindungen zwischen allen Städten? 33 4 Wiederholung Kürzeste Pfade Beispiel: Ablauf Dijkstra-Algorithmus 1 u 1 ∞ v u ∞ s 0 v ∞ 10 2 3 s 5 6 x 2 2 3 0 7 5 Kürzeste Pfade: Algorithmen Dijkstra-Algorithmus ∞ ∞ Beispiel: 1 10 10 y 5 6 7 5 5 x 2 ∞ y Q: Q: (x, 5) (u, 10) (v, ∞) (y, ∞) (s,0) (u, ∞) (v, ∞) (x, ∞) Graph. (y, ∞) Sei G = (V , E ) gewichteter, gerichteter • Kürzeste Pfade in Graphen von fixem Startknoten s: G =v Kantengewichte) (V , E ) Graph mit Gewicht w :E ! R+ (positive reelle • Dijkstra-Algorithmusu(nurSei positive u v 1 1 ∞ 8 13 kürzeste PfadeGreedy-Algorithmus 8 Zahlen). 10 10 Komplexität: O(|E | log |V |) • Startknoten s 2 V für kürzesten Pfad s s 2 3 5 6 0 (nur positive Kantengewichte) • A*-Algorithmus • Graph repräsentiert 2 3 5 6 0 mit Adjazenzliste adj 7 7 Komplexität: mit5guter Heuristik, besser als Dijkstra • HHjeder200Knoten (ausser s)5hat Vorgänger im kürzesten Pfad pred 5 7 5 7 (auch negative Gewichte) 2 • Knoten sind Großstädte• Bellman-Ford-Algorithmus B 250 • jeder Knoten hat Markierung dx 2 x y y 300 Komplexität: O(|V | ⇤ |E |) H • Kanten sind Autobahnverbindung • Distanz (bzgl. Gewicht) von Startknoten s 200 Q: (y, 7) (u, 8) (v, ∞) Q: (u, 8) (v, 13) 350 450 Knotenpaaren: • Kürzeste • Gewichte der Kanten Pfade in Graphen 200 zwischen allen sind (grobe) • Hilfsmittel: Priority Queue Q 44 K DD • Floyd-Warshall-Algorithmus (all pairs shortest path) Entfernungen in Kilometern 200 F 300 basiert auf dynamischer Programmierung 200 300 150 Fragestellungen: Komplexität: ⇥(|V |3 ) N 50 KA • kürzester Weg von M nach HH? Navigationssystem: S • alle kürzesten Verbindungen von M zu anderen Städten? 250 150 M 34 42 • alle kürzesten Verbindungen zwischen allen Städten? 33 4 Algorithmus: Dijkstra Input: Graph G = (V , E ), w : E → R+ , Startknoten s ∈ V Output: Vorgänger-Liste pred, Distanz-Markierung d Dijkstra(G , w , s): for each (Knoten v ∈ V ) { // Initialisierung pred[v ] = NULL; d[v ] = ∞; } d[s] = 0; Q = Priority Queue mit Elementen V , Schlüsseln d; while ( !Q.isEmpty() ) { // Hauptschleife u = Q.extractMin(); for each (v ∈ adj[u] mit v ∈ Q) { if (d[u] + w (u, v ) < d[v ]) { pred[v ] = u; d[v ] = d[u] + w (u, v ); Q.decreaseKey(v , d[v ]); } } } 5 Dijkstra-Algorithmus Nach Ausführung von Dijkstra(G , w , s) gilt für v ∈ V : • d[v ] = Gewicht wmin (v , s) des kürzesten Pfades von v zu s • pred[v ] = Vorgängerknoten • Kürzester Pfad von v zu s: pred[v ], pred[pred[v ]], . . . , s Beispiel: u 1 8 v 9 10 s 2 3 0 5 6 7 5 5 x 2 7 y 6 Dijkstra: Laufzeit Laufzeit: • Annahme: Q implementiert als binärer Min-Heap • Zeile 1-3: O(|V |) • Zeile 5: entspricht buildMinHeap, also O(|V |) • Zeile 6-15: Ausführung |V | mal • Zeile 7: O(log |V |) • Zeile 8-14: Ausführung inkl. äusserer while-Schleife: insgesamt |E | mal (siehe DFS/BFS) • Zeile 12: O(log |V |) Dijkstra(G , w , s): 1 for each (Knoten v ∈ V ) { 2 pred[v ] = NULL; d[v ] = ∞; 3 } 4 d[s] = 0; 5 Q = Priority Queue(V , d); 6 while ( !Q.isEmpty() ) { 7 u = Q.extractMin(); 8 for each (v ∈ adj[u] mit v ∈ Q) { 9 if (d[u] + w (u, v ) < d[v ]) { 10 pred[v ] = u; 11 d[v ] = d[u] + w (u, v ); 12 Q.decreaseKey(v , d[v ]); 13 } 14 } 15 } Gesamt: O (|V | + |E |) log |V | einfacher: O(|E | log |V |) 7 Dijkstra: Komplexität • Komplexität des Dijkstra Algorithmus hängt entscheidend von der Implementierung der Priority Queue ab! • Varianten: • als verkettete Liste: O(|V |2 ) • als binärer Heap: O(|E | log |V |) • als Fibonacci Heap: O(|E | + |V | log |V |) 8 Dijkstra: Korrektheit (nur Beweisidee, dies ist kein formaler Beweis!) Annahme: bisherige Iterationen waren korrekt, bisher bearbeitete Knoten: X ⊂ V • nächster Iterationsschritt nimmt kürzeste direkte Verbindung von Knoten x ∈ X zu noch nicht bearbeitetem Knoten y ∈ V \ X hinzu • d[y ] ist nun d[x] + w (x, y ) • jeder andere Pfad zu y hat entweder • eine Kante, die aus X heraus geht und ist damit nicht kürzer als (x, y ) • mehrere Kanten, und ist damit nicht kürzer als d[y ], da die Kanten positives Gewicht haben Entscheidende Annahme: Kanten haben positives Gewicht! 9 Dijkstra: Anwendungen Dijkstra ist einer der am häufigsten verwendete Graph-Algorithmen Beispiele: • Routenplanung in GIS (Geographic Information System) • Navigationssystem im Auto • Maps Applikation (Google, Bing, Apple etc.) • Routen mit Flugzeugen, Bahn usw. • Routing Protokolle für IP Netzwerke • z.B. Open Shortest Path First • Pfadplanung von Robotern, UAV/Dronen, etc. • Segmentierung von medizinischen Bilddaten 10 Programm heute 7 Fortgeschrittene Datenstrukturen 8 Such-Algorithmen 9 Graph-Algorithmen Tiefensuche Breitensuche Kürzeste Pfade Minimaler Spannbaum 10 Numerische Algorithmen Matrizen 11 Minimaler Spannbaum Sei G = (V , E ) zusammenhängender Graph mit Gewichtsfunktion w : E → R. • Spannbaum: Teilgraph G 0 = (V , E 0 ), der ein Baum ist und alle Knoten von G enthält. • minimaler Spannbaum: Spannbaum G 0 mit minimalem Gewicht wG 0 = X w (x, y ) (x,y )∈E 12 Minimaler Spannbaum: Beispiel Beispiel: 6 (virtuelle) Städte und Kosten für Strassenbau dazwischen (in Million Euro): Awl Dresh 4 0 0 5 2 Rennis 3 0 6 3 2 0 Sadon 0 1 Brous 6 0 Gedry Problem: Strassenbau mit minimalen Kosten, so daß alle Städte verbunden sind (direkt oder über andere Städte) Lösung: minimaler Spannbaum 13 Minimaler Spannbaum: Beispiel 2 Mögliche Lösungen: Awl Dresh 4 0 Awl 0 5 0 1 Dresh 0 2 Rennis 0 4 0 Rennis 3 0 Brous 1 0 Brous 6 2 0 Sadon Gewicht: 18 0 2 0 Gedry Sadon 0 Gedry Gewicht: 12 14 Minimaler Spannbaum: Algorithmen Sei G = (V , E ) zusammenhängender Graph mit Gewichtsfunktion w : E → R. • Minimaler Spannbaum von G : • Algorithmus von Kruskal: Greedy-Algorithmus Komplexität: O(|E | log |V |) • Algorithmus von Prim: Greedy-Algorithmus Komplexität: O(|E | log |V |) • viele Varianten davon als parallele Algorithmen 15 Beispiel-Ablauf: Prim Algorithmus 1 4 1 2 5 2 3 3 6 3 2 5 6 5 4 2 5 2 3 6 6 6 6 1 4 1 3 2 2 5 3 6 3 2 4 1 6 2 5 3 5 4 1 3 3 6 2 2 4 1 4 1 3 6 5 3 2 4 1 6 6 16 Beispiel-Ablauf: Prim Algorithmus 2 4 1 2 5 2 3 3 6 3 2 5 6 5 4 2 5 2 3 6 6 6 6 1 4 1 3 2 2 5 3 6 3 2 4 1 6 2 5 3 5 4 1 3 3 6 2 2 4 1 4 1 3 6 5 3 2 4 1 6 6 17 Beispiel-Ablauf: Prim Algorithmus 3 4 1 2 5 2 3 3 6 5 3 2 3 6 6 2 5 2 4 1 4 1 3 6 5 3 2 4 1 6 6 Beobachtungen: • Zwischenlösungen von Prim Algorithmus sind Bäume • es werden öfters mehrere Kanten zum selben Knoten betrachtet (s. oben) • Vereinfachung: betrachte nur Kante mit minimalem Gewicht 18 Prim Algorithmus Sei G = (V , E ) zusammenhängender Graph mit Gewichtsfunktion w : E → R. • Startknoten s ∈ V für minimalen Spannbaum • Graph repräsentiert als Adjazenzliste adj • jeder Knoten (ausser s) hat Vorgänger im Spannbaum pred • jeder Knoten hat Markierung g • kleinstes Gewicht um Knoten mit aktuellem Spannbaum zu verbinden • Hilfsmittel: Priority Queue Q 19 Algorithmus: Prim Input: Graph G = (V , E ), w : E → R, Startknoten s ∈ V Output: Vorgänger-Liste pred Prim(G , w , s): for each (Knoten v ∈ V ) { // Initialisierung pred[v ] = NULL; g[v ] = ∞; } g[s] = 0; Q = Priority Queue mit Elementen V , Schlüsseln g; while ( !Q.isEmpty() ) { // Hauptschleife u = Q.extractMin(); for each (v ∈ adj[u] mit v ∈ Q) { if (w (u, v ) < g[v ]) { pred[v ] = u; g[v ] = w (u, v ); Q.decreaseKey(v , g[v ]); } } } 20 Beispiel: Ablauf Prim Algorithmus 1 u v 8 ∞ 4 u ∞ 4 2 s r 0 11 7 8 (s,0) y 4 u 7 8 8 x y Q: (v, 8) (x, 8) (r, ∞) (y, ∞) (z, ∞) 2 8 r 0 11 ∞ 8 z x Q: (r, 2) (z, 4) 4 2 7 8 ∞ ∞ z 2 s 4 6 1 2 v 8 4 4 ∞ y Q: (u, 4) (x, 8) (r, ∞) (v, ∞) (y, ∞) (z, ∞) 8 r 11 ∞ 1 x 2 s 6 8 z 4 ∞ 7 ∞ v 8 4 0 2 (u, ∞) (v, ∞) (r, ∞) (x, ∞) (y, ∞) (z, ∞) u 11 8 ∞ 1 x Q: r 0 6 ∞ ∞ 2 s 4 ∞ v 8 4 6 1 ∞ y 2 4 z (x, 8) (y, ∞) 21 Beispiel: Ablauf Prim Algorithmus 2 u v 8 4 4 u 8 4 2 s r 0 11 7 8 (z, 4) y 4 u 8 8 7 x Q: (y, 2) (x, 7) 4 z y r 0 11 2 4 1 z x 4 2 7 8 2 8 2 s 4 6 1 2 v 8 4 4 2 7 y Q: (z, 4) (x, 7) (y, 6) r 11 6 1 x 2 s 6 7 z 4 2 7 4 v 8 4 0 2 (x, 8) (y, ∞) u 11 8 ∞ 1 x Q: (r, 2) r 0 6 8 8 2 s 4 2 v 8 4 6 1 2 y 2 4 z Q: (x, 1) 22 Beispiel: Ablauf Prim Algorithmus 3 u v 8 4 4 u 8 4 2 s r 0 11 7 8 1 x Q: (x, 1) r 0 6 1 y 11 2 4 1 z 4 2 7 8 2 8 2 s 4 2 v 8 4 x 6 1 2 y 2 4 z Q: Nach Ausführung von Prim(G , w , s) gilt für v ∈ V : • pred[v ] = Vorgängerknoten im Spannbaum • Pfad in Spannbaum von v zu Wurzel s: pred[v ], pred[pred[v ]], . . . , s 23 Prim: Laufzeit Laufzeit: • Annahme: Q implementiert als binärer Min-Heap • Zeile 1-3: O(|V |) • Zeile 5: entspricht buildMinHeap, also O(|V |) • Zeile 6-14: Ausführung |V | mal • Zeile 7: O(log |V |) • Zeile 8-13: Ausführung inkl. äusserer while-Schleife: insgesamt |E | mal (siehe DFS/BFS) • Zeile 11: O(log |V |) Prim(G , w , s): 1 for each (Knoten v ∈ V ) { 2 pred[v ] = NULL; g[v ] = ∞; 3 } 4 g[s] = 0; 5 Q = Priority Queue(V , g); 6 while ( !Q.isEmpty() ) { 7 u = Q.extractMin(); 8 for each (v ∈ adj[u] mit v ∈ Q) { 9 if (w (u, v ) < g[v ]) { 10 pred[v ] = u; g[v ] = w (u, v ); 11 Q.decreaseKey(v , g[v ]); 12 } 13 } 14 } Gesamt: O (|V | + |E |) log |V | einfacher: O(|E | log |V |) 24 Prim: Komplexität • Komplexitätsanalyse von Prim fast identisch mit Dijkstra! • Komplexität des Algorithmus von Prim hängt entscheidend von der Implementierung der Priority Queue ab! • Varianten: • als verkettete Liste: O(|V |2 ) • als binärer Heap: O(|E | log |V |) • als Fibonacci Heap: O(|E | + |V | log |V |) 25 Prim: Anwendungen • Planung von Netzwerken • Strassennetz • Kommunikations-Netzwerk • elektronische Schaltungen • Clustering von Daten • Daten als Knoten, “Nähe” als Kanten, entferne “lange” Kanten aus minimalem Spannbaum → Clustering • Extrahieren/Tracking von Objekten aus Bildern in Computer Vision 26 Ausblick: Graphen-Algorithmen • Fluss in Graphen: statt Kantengewichten gibt es Kapazitäten, betrachtet wird Fluss von Quelle zu Senke • Problem: finde maximalen Fluss • Anwendung: z.B. Fluss in Kommunikations-Netzwerken • Einfärben von Graphen: Färbe Knoten von Graph so ein, dass keine benachbarten Knoten diesselbe Farbe haben • Anwendungen: z.B. Scheduling, Sudoku • Planare Graphen: lässt sich Graph ohne Kanten-Überschneidung zeichnen? • Anwendung: z.B. Chip- bzw. Platinen-Design • Klassifikation von medizinischen Daten: über analytische Operationen auf Adjazenzmatrix, z.B. Laplace-Operator • Anwendungen: z.B. Identifikation von Melanomen, Tracking von Endoskopen 27 Programm heute 7 Fortgeschrittene Datenstrukturen 8 Such-Algorithmen 9 Graph-Algorithmen Tiefensuche Breitensuche Kürzeste Pfade Minimaler Spannbaum 10 Numerische Algorithmen Matrizen 28 What is the matrix? Was ist eine Matrix? • Anordnung von Zahlen (aji ) ⊂ R in einem m × n Muster: a11 .. . am1 · · · a1n .. =: A .. . . · · · amn • Element des Vektorraumes Rm×n A ∈ Rm×n • Lineare Abbildung f : Rn → Rm mit f (x) = Ax wobei A m × n Matrix. 29 Beispiel: Anwendung von Matrizen • Adjazenzmatrix von Graphen • effizienter als Adjazenzlisten für dichte Graphen (viele Kanten) • erlaubt analytische Operationen wie Laplace-Operator/Eigenwerte • Bilder im Computer: gespeichert als Matrix 30 Speicherung von Matrizen Speicherung als sequentielle Liste / Array: • row-major: Zeilen werden zuerst durchlaufen a11 a12 a13 a21 a22 a23 a31 a32 a33 ⇒ [a11 , a12 , a13 , a21 , a22 , a23 , a31 , a32 , a33 ] • column-major: Spalten werden zuerst durchlaufen a11 a12 a13 a21 a22 a23 a31 a32 a33 ⇒ [a11 , a21 , a31 , a12 , a22 , a32 , a13 , a23 , a33 ] 31 Matrix-Operationen Seien A, B ∈ Rm×n mit A = (aji ), B = (bji ) und λ ∈ R. • Addition: a11 + b11 · · · a1n + b1n .. .. .. A+B = . . . am1 + bm1 · · · amn + bmn • Skalarmultiplikation: λa11 .. λA = . λam1 · · · λa1n .. .. . . · · · λamn 32 Matrix-Operationen (Fortsetzung) Seien A = (aji ) ∈ Rm×n , x = (xi ) ∈ Rn und B = (bji ) ∈ Rn×r . • Matrix-Vektor-Multiplikation: a11 x1 + . . . + a1n xn .. A·x = . am1 x1 + . . . + amn xn • Matrix-Matrix-Multiplikation: a11 b11 + . . . + a1n bn1 · · · a11 b1r + . . . + a1n bnr .. .. .. A·B = . . . am1 b11 + . . . + amn bn1 · · · am1 b1r + . . . + amn bnr 33 Matrix-Multiplikation n m r • r = n m 34 Matrix-Multiplikation 2 n m r • r = n m 35 Matrix-Multiplikation 3 n m r • r = n m 36 Matrix-Multiplikation: Komplexität Seien A = (aji ) ∈ Rn×n und B = (bji ) ∈ Rn×n (quadratisch). a11 b11 + . . . + a1n bn1 · · · a11 b1n + . . . + a1n bnn .. .. .. A·B = . . . an1 b11 + . . . + ann bn1 · · · an1 b1n + . . . + ann bnn Komplexität: • pro Eintrag: n Additionen, n Multiplikationen • insgesamt n2 Einträge • A · B also n3 Additionen und n3 Multiplikationen • Komplexität: Θ(n3 ) arithmetische Operationen 37 Beispiel: Anwendung von Matrix-Multiplikation • Wechsel von Koordinaten-Systemen können als Matrix-Vektor-Multiplikation dargestellt werden • Matrix heisst hier auch Transformation • mehrere Wechsel hintereinander können mittels Matrix-Matrix-Multiplikation zu einer Transformation zusammengefasst werden Beispiel: Augmented Reality Kamera Transformation Transformation Bildschirm Welt 38 Demo: Augmented Reality Augmented Reality Demo 39 Matrix-Multiplikation: Strassen-Algorithmus Seien A, B ∈ Rn×n mit n 2er-Potenz (n = 2k ), n > 1. • Divide & Conquer Ansatz zur Matrizen-Multiplikation • A, B aufteilen in vier n/2 × n/2 Matrizen: a11 a12 A= , a21 a22 B= b11 b12 b21 b22 • Produkt A · B berechnen als: A·B = a11 b11 + a12 b21 a11 b12 + a12 b22 a21 b11 + a22 b21 a21 b12 + a22 b22 • aik bkj ist selbst Matrix-Matrix-Produkt • rekursiv aufteilen bis 1 × 1 Produkt • Komplexität: immer noch Θ(n3 ) 40 Strassen-Algorithmus • Berechne: q1 = (a11 + a22 ) · (b11 + b22 ) q2 = (a21 + a22 ) · b11 q3 = a11 · (b12 − b22 ) q4 = a22 · (b21 − b11 ) q5 = (a11 + a12 ) · b22 q6 = (a21 − a11 ) · (b11 + b12 ) q7 = (a12 − a22 ) · (b21 + b22 ) • Dann ist: q1 + q4 − q5 + q7 q3 + q5 A·B = q2 + q4 q1 + q3 − q2 + q6 • Komplexität: Θ(nlg 7 ) = Θ(n2.807 ) 41 Matrix-Matrix-Multiplikation Seien A, B ∈ Rn×n . • naiver Algorithmus: Θ(n3 ) • Strassen-Algorithmus (1969): Θ(n2.807 ) • weniger numerisch stabil als naiver Algorithmus • n muss 2er-Potenz sein • benötigt deutlich mehr Speicher als naiver Algorithmus • Coppersmith-Winograd Algorithmus (1987): O(n2.376 ) • erst praktikabel für Grössen, die mit heutigen Computern nicht bearbeitet werden können • es existieren verbesserte Varianten (2011) mit O(n2.3727 ) 42 Zusammenfassung 7 Fortgeschrittene Datenstrukturen 8 Such-Algorithmen 9 Graph-Algorithmen Tiefensuche Breitensuche Kürzeste Pfade Minimaler Spannbaum 10 Numerische Algorithmen Matrizen 43