Customization (Zuschneiden) Anpassen der (Graph)Datenstruktur an die Anwendung. I Ziel: schnell, kompakt. I benutze Entwurfsprinzip: make the common case fast I Listen vermeiden Mögliches Problem: Software-Engineering-Alptraum Möglicher Ausweg: Trennung von Algorithmus und Repräsentation 317 Beispiel: DAG-Erkennung Vgl. Folie 73ff. (dort aber Test auf Ausgangsgrad)! Function isDAG(G = (V , E )) // Adjazenzarray! dropped:= 0 compute array inDegree of indegrees of all nodes // Zeit O(m)! droppable={v 2 V : inDegree[v ] = 0} : Stack while droppable 6= 0/ do invariant G is a DAG iff the input graph is a DAG v := droppable.pop dropped++ foreach edge (v , w ) 2 E do inDegree[w ] if inDegree[w ] = 0 then droppable.push(w ) return |V | = dropped Laufzeit: O(m + n) (auch ohne dynamische Graphdatenstruktur!) 318 Adjazenz-Matrix A 2 {0, 1}n⇥n with A(i, j) = [(i, j) 2 E ] + platzeffizient für sehr dichte Graphen platzineffizient sonst. Übung: was bedeutet “sehr dicht” hier? + einfache Kantenanfragen langsame Navigation ++ verbindet lineare Algebra und Graphentheorie Beispiel: C = Ak . Cij =# k-Kanten-Pfade von i nach j Wichtige Beschleunigungstechniken: 2 1 0 0 B 0 B @ 0 0 4 3 1 0 1 0 1 1 0 0 I O(log k) Matrixmult. für Potenzberechnung I Matrixmultiplikation in subkubischer Zeit, z. B., Strassens Algorithmus 1 0 1 C C 1 A 0 319 Pfade zählen mittels LA Adjanzenzmatrix: A 2 {0, 1}n⇥n mit A(i, j) = [(i, j) 2 E ] Sei C := Ak . Behauptung: Cij =# k-Kanten-Pfade von i nach j. Beweis: IA (k = 1) C = A1 = A stimmt nach Definition von A. Schluss k k + 1: Cij = (Ak A)ij = Â Aki` A`j 2 1 4 ` Aki` =#k-Kanten-Pfade von i nach ` (nach IV). Aki` A`j =#k + 1-Kanten-Pfade von i nach j mit (`, j) als letzter Kante. Jede mögliche letzte Kante wird genau einmal gezählt. Übung: zähle Pfade der Länge k 3 0 0 B 0 B @ 0 0 1 0 1 0 1 1 0 0 1 0 1 C C 1 A 0 320 Beispiel, wo Graphentheorie bei LA hilft Problemstellung: löse Bx = c Sei G = (1..n, E = {{i, j} : Bij 6= 0}) Nehmen wir an, G habe zwei Zusammenhangskomponenten ) tausche Zeilen und Spalten derart, dass ✓ ◆✓ ◆ ✓ ◆ B1 0 x1 c1 = 0 B2 x2 c2 zu lösen bleibt. Übung: Was passiert, wenn (1..n, E = {(i, j) : Bij 6= 0}) ein DAG ist? 321 Implizite Repräsentation Kompakte Repräsentation möglicherweise sehr dichter Graphen Implementiere Algorithmen direkt mittels dieser Repräsentation Beispiel: Intervall-Graphen Knoten: Intervalle [a, b] ✓ R Kanten: zwischen überlappenden Intervallen 322 Zusammenhangstest für Intervallgraphen V = {[a1 , b1 ], . . . , [an , bn ]} E = {{[ai , bi ], [aj , bj ]} : [ai , bi ] \ [aj , bj ] 6= 0} / Idee: durchlaufe Intervalle von links nach rechts. Die Anzahl überlappender Intervalle darf nie auf null sinken. Annahme: Startpunkte in Sortierung vor Endpunkten! Function isConnected(L : SortedListOfIntervalEndPoints) : {0, 1} remove first element of L; overlap := 1 foreach p 2 L do if overlap= 0 return false if p is a start point then overlap++ else overlap // end point return true O(n log n) Algorithmus für bis zu O n2 Kanten! Übung: Zusammenhangskomponenten finden 323 Beispiel Function isConnected(L : SortedListOfIntervalEndPoints) : {0, 1} remove first element of L; overlap := 1 foreach p 2 L do if overlap= 0 return false if p is a start point then overlap++ else overlap return true // end point 324 Graphrepräsentation: Zusammenfassung I Welche Operationen werden gebraucht? I Wie oft? I Adjazenzarrays gut für statische Graphen I Pointer I Matrizen eher konzeptionell interessant flexibler, aber auch teurer 325 Kap. 9: Graphtraversierung Ausgangspunkt oder Baustein fast jedes nichttrivialen Graphenalgorithmus 326 Graphtraversierung als Kantenklassifizierung forward s tree backward cross 327 Breitensuche Baue Baum von Startknoten s, der alle von s erreichbaren Knoten mit möglichst kurzen Pfaden erreicht. Berechne Abstände: b s 0 e g c d f 1 2 tree backward cross forward 3 328 Breitensuche I Einfachste Form des Kürzeste-Wege-Problems I Umgebung eines Knotens definieren (ggf. begrenzte Suchtiefe) I Einfache, effiziente Graphtraversierung (auch wenn Reihenfolge egal) b s 0 e g c d f 1 2 tree backward cross forward 3 329 Breitensuche Algorithmenidee: Baum Schicht für Schicht aufbauen b s 0 e g c d f 1 2 tree backward cross forward 3 330 Function bfs(s) : Q:= hsi // aktuelle Schicht while Q 6= hi do exploriere Knoten in Q merke dir Knoten der nächsten Schicht in Q 0 Q:= Q 0 b s 0 e g c d f 1 2 tree backward cross forward 3 331