Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Programmieren 2 Future Car Projekt Praktikum 6

Ähnliche Präsentationen


Präsentation zum Thema: "Programmieren 2 Future Car Projekt Praktikum 6"—  Präsentation transkript:

1 Programmieren 2 Future Car Projekt Praktikum 6
Speichern von Graphen - Suchen in Graphen Kürzeste Wege Reiner Nitsch

2 Darstellung von Graphen als Array von Listen
Grundlagen zu Graphen (siehe Vorlesung Mathematik 1) 1 2 3 4 5 6 Adjazenzlisten Die mit Knoten 5 verbunden Nachbarknoten (= Kantenmenge E5 ) Array von Adjazenzlisten 1 6 2 5 3 4 Ungerichteter Graph G(V,E) V: Knotenmenge E: Kantenmenge Bietet Antwort auf Fragen zu Graphen G wie z.B. Speicherbedarf?  proportional zur Anzahl Knoten plus Anzahl Kanten  O(|V|+|E|) Wieviele Kanten enden an vi? Welche Nachbarn vj hat vi? Existiert Kante E=(vi,vj)?  O(|Ei|) Gewichteter Graph: Gewicht als zu-sätzliche Info der Listenelemente 1 6 2 5 3 4 Gerichteter Graph Projekt FutureCar

3 Darstellung von Graphen mit Adjazenzmatrix
Adjazenzmatrix a mit Elementen aij aij = 1 wenn Kante E=(vi,vj) in G enthalten, sonst aij=0 1 6 2 5 3 4 Ungerichteter Graph G(V,E)  aij = aji (symmetrisch) 1 2 3 4 5 i j Bietet Antwort auf Fragen zu Graphen G wie z.B. Welche Kanten enden an vi? Welche Nachbarn vj hat vi? Existiert Kante E=(vi,vj)?  O(1) Speicherbedarf? O(|V|2)  ungünstig wenn G wenige Kanten hat Gewichteter Graph: Gewicht an Stelle von '1' in Matrix eintragen 1 6 2 5 3 4 Gerichteter Graph G(V,E)  aij ≠ aji (unsymmetrisch) Projekt FutureCar

4 Adjazenzliste des Graphen der FutureCar World
1,1 1,2 3,1 2,1 3,2 2,2 1,3 4,2 # Rasterkarte (Grid) von FC-City 1 4 0,0 1,0 2,0 3,0 0,1 1,1 2,1 3,1 0,2 1,2 2,2 3,2 0,3 1,3 2,3 3,3 x y Rasterkarte von FC-City mit XY-Koordinaten 2 Adjazenzlisten Adjazenzlisteninfo als Textsequenz 5 Graph zur Modellierung der Erreichbarkeitsbeziehungen zwischen den Zellen der Rasterkarte 3 Projekt FutureCar

5 Implementierungsempfehlungen
Node + loc + adjList + Konstruktor: 1,1 1,2 2,1 2,2 1,3 3,2 3,1 4,2 3,1 2,1 3,2 3,1 2,1 3,2 1 1..N Graph - nodes:Node[ ] + Graph(filename:string) + … Adjazenzlisten Empfehlungen: Container zum Verwalten der Knoten? Knoten in Container einfügen? Was sollte in den Adjazenzlisten gespeichert werden? Welcher Datentyp eignet sich für Route? map<Location, Node> nodes nodes[ loc ] = Node(…) Location oder Adressen der Nachbarknoten. Verwendbarkeit im Navi sicherstellen (Siehe Praktikum 5) Projekt FutureCar

6 Traversieren von Graphen
Als Traversieren bezeichnet man das systematische Besuchen aller Knoten und das Durchlaufen jeder Kante eines Graphen. Algorithmen zum Traversieren eines Graphen dienen als Basis für viele andere grundlegende Algorithmen zur Verarbeitung von Graphen Man unterscheidet zwischen Breitentraversierung (breadth-first search, BFS): Die Knoten werden geordnet nach der "Entfernung" von einem Startknoten durchlaufen zuerst alle Knoten mit 1 Kantenlänge Abstand vom Startknoten danach alle diejenigen Knoten mit Abstand 2, danach die mit Abstand 3, usw. Tiefentraversierung (depth-first search, DFS): Dieser Algorithmus erhöht immer zuerst die Distanz vom Startknoten, bevor er in die Breite geht und Nachbarknoten mit gleicher Distanz besucht (meist rekursiv implementiert) Bereits besuchte Knoten müssen markiert werden, weil sich die Algorithmen sonst in den Kreisen des Graphen verlieren. BFS: Der Gewissenhafte DFS: Der Neugierige Node + loc:Location + adjList + visited:bool + Konstruktor: Markierung Projekt FutureCar

7 Tiefentraversierung (Rekursiv)
Rekursiver Algorithmus (in Pseudocode), der ausgehend von einer unmarkierten Ecke vi, alle anderen Knoten vj, j!=i eines Graphen G (genauer: einer Komponente desselben) besucht Node + loc:Location + adjList + visited:bool + Konstruktor: Funktion: traverse-dfs(v) Zweck: Tiefensuche in einem Graphen Parameter v: Ecke bei dem die Suche beginnt PRE: --- POST: Alle Ecken, die von v erreichbar sind, sind gefunden. Markiere v als besucht Bestimme einen Nachbarknoten von v und nenne diesen vnext WHILE(vnext existiert UND noch nicht besucht ist) beginne weitere Tiefensuche bei vnext Wieder zurück, bestimme weiteren Nachbarknoten von v und nenne diesen wieder vnext END WHILE procedure traverse-dfs(v) visited(v) := true vnext := adjList[v] WHILE( exist(vnext) UND NOT visited(vnext) traverse-dfs(vnext) vnext := succ(v_next) END WHILE Projekt FutureCar

8 Tiefentraversierung (Rekursiv)
Rekursiver Algorithmus (in Pseudocode), der ausgehend von einer unmarkierten Ecke vi, alle anderen Knoten vj, j!=i eines Graphen G (genauer: einer Komponente desselben) besucht PRE: POST: Alle Ecken, die von v erreichbar sind, sind markiert. procedure traverse-dfs(v) visited(v) := true // markiere v als besucht v_next := adjList[v] // hole ersten Nachbarknoten while exist(v_next) do { // solange einer existiert if not visited(v_next) do // und dieser noch nicht besucht ist traverse-dfs(v_next) // gehe erst mal zu diesem (Rekursion!!) // wieder zurück v_next := succ(v_next) // hole nächsten Nachbarknoten } Node + loc:Location + adjList + visited:bool + Konstruktor: Projekt FutureCar

9 Beispiel zur Tiefentraversierung
procedure traverse-dfs(v) visited(v) := true vnext := adjList[v] WHILE( exist(vnext) UND NOT visited(vnext) traverse-dfs(vnext) vnext := succ(v_next) END WHILE 1 2 3 4 5 6 1 2 4 Adjazenzlisten von Seite 2 2 5 4 1 3 5 6 4 1 2 5 5 4 3 2 6 3 6 Startknoten Komplexität: O(|V|+|E|) 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 Alle Knoten und Kanten besucht! Projekt FutureCar

10 Tiefentraversierung (Iterativ)
Iterativer Algorithmus mit einem Stack, der ausgehend von einer unmarkierten Ecke vi, alle anderen Knoten vj, j!=i eines Graphen G (genauer: einer Komponente desselben) besucht PRE: POST: Alle Ecken, die von v erreichbar sind, sind markiert. procedure traverse-dfs(v) t := empty-stack // t ist ein lokaler Stack visited(v) := true // markiere v als besucht push(t,v) // lege v auf den Stack WHILE NOT empty(t) DO { v := top(t) // hole oberstes Element aus Stack vnext := adjList[v] // hole ersten Nachbarknoten WHILE exist(vnext) AND visited(vnext) DO // schon besucht? vnext := succ(vnext) // Ja! Dann eben den Nächsten END WHILE IF exist(vnext) DO // Noch einen Unbesuchten gefunden? visit(vnext) // diesen besuchen (und bearbeiten), visited(vnext) := true // als "besucht" markieren und push(t,vnext) // Erst mal auf den Stack damit ... ELSE DO pop(t) END IF END WHILE // Erledigt! Alle Nachbarn von v besucht } … und hier schon wieder runter! Projekt FutureCar

11 Breitentraversierung
Iterativer Algorithmus, der alle Knoten eines zusammenhängenden Graphen geordnet nach der Entfernung vom Startknoten v durchläuft. Zuerst werden alle vom Startknoten über 1 Kante erreichbaren Knoten besucht Danach alle über mindestens 2 Kanten erreichbaren Knoten, usw. Entsteht formal aus Tiefentraversierung, wenn man den Stack durch eine Queue ersetzt. PRE: --- Post: Alle Knoten, die von v erreichbar sind, sind markiert, also besucht worden procedure bfs_node(v) t := empty-queue // Definition einer leeren lokalen Queue visited(v) := true // Starknoten v als "besucht" markieren enqueue(t,v) WHILE NOT empty(t) DO v := front(t) // vordersten Knoten in t lesen vnext := adjList[v] // hole ersten Nachbarknoten WHILE exist(vnext) AND visited(vnext) DO // schon besucht? vnext := succ(vnext) // Ja! Dann eben den Nächsten END WHILE IF exist(vnext) DO // Noch einen Unbesuchten gefunden? visit(vnext) // diesen besuchen (und bearbeiten), visited(vnext) := true // als "besucht" markieren und enqueue(t,v_next) // erst mal in queue einreihen, wo sie bis zur // Bearbeitung ihrer Nachbarknoten warten ELSE DO dequeue(t) // Erledigt! Alle Nachbarn von v wurden besucht END IF END WHLE Die Änderungen gegenüber der Tiefensuche sind ROT markiert! Projekt FutureCar

12 Beispiel zur Breitentraversierung
procedure bfs_node(v) t := empty-queue visited(v) := true enqueue(t,v) WHILE NOT empty(t) DO v := front(t) vnext := adj[v] WHILE exist(vnext) AND visited(vnext) DO vnext := succ(vnext) IF exist(vnext) DO visit(v_next) visited(vnext) := true enqueue(t,vnext) ELSE dequeue(t) END IF END WHILE 1 2 3 4 5 6 1 2 4 Adjazenzlisten von Seite 2 2 5 4 1 3 5 6 4 1 2 5 5 4 3 2 t: Queue 6 3 6 2 5 4 1 3 6 Startknoten 1 6 2 5 3 4 2 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 Jetzt sind alle Knoten mit Distanz "1Kante" zum Startknoten besucht 5 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 1 6 2 5 3 4 Alle Knoten und Kanten besucht! Projekt FutureCar

13 Kürzeste Wege mittels Breitensuche
Gesucht ist eine Verbindung (Pfad) zwischen 2 Knoten: Tiefensuche liefert eine entsprechende Kantenfolge, wenn es eine gibt (aber nicht unbedingt die Kürzeste). Breitensuche liefert garantiert die Kürzeste. Aufgabe Mit Hilfe eines Breitensuchverfahrens soll der kürzeste Weg in einem ungewichteten Graphen G vom Startpunkt src zum Zielknoten dest gefunden werden, der über die geringste Anzahl von Kanten verläuft. Dabei wird der Weg so codiert, dass man ihn hinterher rekonstruieren kann. Lösung Die Breitentraversierung durchläuft alle Knoten geordnet nach der Kantendistanz zu src. Der Vorgängerknoten, von dem ausgehend der Knoten v betreten wird, verbindet somit v auf dem kürzesten Wege mit src (keine Kantengewichte!). Im Bearbeitungsschritt merkt sich Knoten v daher seinen Vorgängerknoten Nachdem Knoten dest betreten wurde und dieser sich seinen Vorgängerknoten gemerkt hat, ist die Suche beendet. Der kürzeste Weg, der dest mit src verbindet, ergibt sich nun, indem man, beginnend bei dest, die Folge der Vorgängerknoten rekonstruiert. Rückwärts gelesen (std::reverse) ergibt diese Folge den gesuchten kürzesten Weg. Projekt FutureCar

14 Breitensuche des Knotens d ausgehend vom Startknoten s
PRE: exist(s), exist(d) POST: Alle Knoten, die von v erreichbar sind, sind markiert, also besucht worden procedure bf_search(s,d) t := empty-queue // Definition einer leeren lokalen Queue visited(s) := true // Starknoten v als "besucht" markieren pred(s) := nil // s kennt seinen Vorgänger noch nicht enqueue(t,s) WHILE NOT empty(t) AND front(t)!=d DO // Abbruch der Suche wenn d besucht v := front(t) // vordersten Knoten in t lesen vnext := adj[v] // hole ersten Nachbarknoten WHILE exist(v_next) AND visited(v_next) DO vnext := succ(vnext) // Bereits besuchte Knoten überspringen END WHILE IF vnext != nil DO // Solange unbesuchte Nachbarknoten zu v existieren visit(vnext) // diese besuchen (und bearbeiten), pred(vnext) := v // Vorgänger merken (besuchen & bearbeiten) visited(vnext) := true // als solche markieren und enqueue(t,vnext) // in queue einfügen, wo sie bis zur Bearbeitung // ihrer Nachbarknoten warten ELSE DO dequeue(t) // entferne vorderstes Element aus t END IF // Alle Nachbarn dieses Knotens sind besucht IF empty(t) DO { kein Pfad von s nach d} ELSE DO reverse(t) END IF Ergänzungen zum vorherigen Algorithmus sind ROT markiert Node + loc:Location + adjList + pred + visited:bool + Konstruktor: Verweis auf Vorgängerknoten Projekt FutureCar


Herunterladen ppt "Programmieren 2 Future Car Projekt Praktikum 6"

Ähnliche Präsentationen


Google-Anzeigen