9.3 Traversieren und Suchen Vor.: Von einer „Wurzel“ w aus seien alle Ecken erreichbar Def.: Die Expansion X(w) des Graphen G=(E,K) ist a) w selbst, wenn w keine Nachfolger hat; sonst: b) mit den Nachfolgern {v1, v2, .....} der ungeordnete Vielwegbaum (w, {X(v1), X(v2), .....}) (ist unendlich, wenn G Zyklen bzw. Kreise enthält!) a b a b c d d b c alp3-9.3 b c c a a b c d1 9.3.1 Tiefendurchlauf Def.: Tiefendurchlauf von G ab w = Durchlauf von X(w) in Präordnung mit Ignorierung von Unterbäumen mit bereits besuchter Wurzel (wenn der Graph kein Baum ist!) (Entsprechend: Tiefensuche nach Ecke mit Eigenschaft e) Besuchte Knoten werden markiert und dadurch wiedererkannt! a b a b c d d b c alp3-9.3 b c c a a b c d package Graph; // all nodes should be considered // to form ONE graph (see 9.2.3) // not generic - for easier presentation public class Node { private boolean visited; private final Set<Node> succ = new TreeSet<Node>(); ..... // just mark all reachable nodes, no further action: public void depthFirstTraversal(){ if(!visited) { visited = true; for(Node n: succ) n.depthFirstTraversal(); } } } Bemerkungen: depthFirstTraversal ist interner Iterator Markierung sichert auch Termination (falls Zyklen!) alp3-9.3 Markierung kann nach der Schleife wieder gelöscht werden - dann aber Mehrfachbesuche (falls kein Baum) Flexiblere Alternative: depthFirstTraversal nicht als interner Iterator, sondern als externer Algorithmus - typischerweise mit Benutzung eines internen Iterators für das Durchlaufen der Nachfolger eines Knotens: public void iterate(Action a){ for(Node n: succ) a.act(n); } public interface Action { void act(Node x); } alp3-9.3 4 class DepthFirst implements Node.Action { public void act(Node n) { traversal(n); } public void traversal(Node x){ if(!x.visited) { x.visited = true; x.iterate(this); } } } Und damit new DepthFirst().traversal(start); ( visited muss public sein) alp3-9.3 5 ... und in Haskell: besuchte Ecken werden in Akkumulator memoriert (keine Datenabstraktion): graph = [ [...], [...], ..... ] -- Liste von Adjazenzlisten dft :: [Int] -> -- Akkumulator Anwendung: Int Ecke -> [Int] Erreichbare Ecken dft [] root dft list node -- erweitert list um alle -- von node aus erreichbaren Ecken | node `elem` list = list -- und falls node noch nicht erfasst: | otherwise = foldl dft (node:list) (graph!!node) alp3-9.3 Zum Nacharbeiten: warum ist das korrekt? 6 9.3.2 Breitendurchlauf Def.: Breitendurchlauf von G ab w = Breitendurchlauf von X(w) mit Ignorierung von Unterbäumen mit bereits besuchter Wurzel, typischerweise auch mit internem Iterator Beispiel Breitensuche „nach roter Ecke“ (vgl. 6.4.4): interface Predicate<X> { boolean holds(X x); } breadthFirstSearch(Predicate<Node>() {public boolean holds(Node p){ return p.colour=="red";}}) alp3-9.3 7 public Node breadthFirstSearch(Predicate<Node> p) throws NotFound { Queue<Node> q = new LinkedList<Node>(); q.add(this); do{ Node n = q.remove(); if(p.holds(n)) return n; n.visited = true; for(Node succ: n.succ) if(!succ.visited) q.add(succ); } while(!q.isEmpty()); throw new NotFound(); } alp3-9.3 8 9.3.3 Spannbäume Def.: Fluten eines Graphen: Information wird von einem Startknoten an alle (erreichbaren) Knoten weitergegeben Das Fluten kann wahlweise mit Breiten*- oder Tiefendurchlauf durchgeführt werden. Durch den Informationsfluss wird ein Baum aufgespannt, der sogenannte (Breiten- oder Tiefen-)Spannbaum (spanning tree) * alp3-9.3 In nichtsequentiellen Systemen - z.B. Rechnernetzen bietet sich Breitendurchlauf an! 9 b a d c a a b d d b c Breiten-Spannbaum ab a c Tiefen-Spannbaum ab a alp3-9.3 10 Fluten mit Tiefendurchlauf (9.3.1, S. 4/5, hier generisch): class Flooding<T> implements Action<T> { private T info; public Flooding(T i) { info = i; } public void act(Node<T> n) { n.info = info; flood(n); } public void flood(Node<T> x){ if(!x.visited) { x.visited = true; x.iterate(this); } } } Und damit z.B. new Flooding<String>("hi!").flood(start); alp3-9.3 11 Def.: Spannbaum S eines ungerichteten, gewichteten, zusammenhängenden Graphen G: freier Baum mit Kanten aus G und allen Ecken aus G Def.: minimaler Spannbaum S: Spannbaum mit minimalen Kosten (d.h. Summe der Kantengewichte) Ein minimaler Spannbaum „dünnt die Kantenmenge des Graphen so aus“, das eine möglichst große Kostenersparnis erzielt wird, ohne dass der Graph zerfällt (9.5). alp3-9.3 12