Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.

Link zu der Vergleichsansicht

Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung
Nächste Überarbeitung
Vorherige Überarbeitung
talit:algorithmen [2024-06-03 05:51] hoftalit:algorithmen [2025-03-03 21:01] (aktuell) – [Aufgabe 4 - Graph Walk] hof
Zeile 16: Zeile 16:
 Wie könnten wir das Weg-Problem (von der KSR an den Bahnhof) abstrakt erfassen? Wir könnten die verschiedenen Wege zum Beispiel so erfassen: Wie könnten wir das Weg-Problem (von der KSR an den Bahnhof) abstrakt erfassen? Wir könnten die verschiedenen Wege zum Beispiel so erfassen:
  
 +<figure graph_romis>
 {{:talit:pasted:20220423-154956.png?600}} {{:talit:pasted:20220423-154956.png?600}}
 +<caption>Graph mit drei Pfaden zum Bahnhof</caption>
 +</figure>
  
 Aus was besteht ein Graph? Aus **Knoten** (en. _nodes_ oder _vertices_) und **Kanten** (_edges_). In unserem Fall haben die Kanten **Gewichte**, die die Länge oder Fahrtdauer der einzelnen Strecken repräsentieren. Aus was besteht ein Graph? Aus **Knoten** (en. _nodes_ oder _vertices_) und **Kanten** (_edges_). In unserem Fall haben die Kanten **Gewichte**, die die Länge oder Fahrtdauer der einzelnen Strecken repräsentieren.
  
-Wie könnten wir diesen Graphen in Python repräsentieren +Wie könnten wir diesen Graphen in Python repräsentieren? 
-?+
 #### Adjazenzmatrix #### Adjazenzmatrix
  
Zeile 110: Zeile 113:
 </code> </code>
 ++++ ++++
- 
 ### Tiefensuche ### Tiefensuche
  
 Bevor wir den schnellsten Weg an den Bahnhof zu finden versuchen, wären wir schon mal nur froh, überhaupt einen Weg zu finden. Es könnte ja auch sein, dass wir uns in die Turnhalle begeben, von wo kein Weg zum Bahnhof führt. Oder dass wir von der Bahnhofstrasse zurück zur KSR gelangen: Bevor wir den schnellsten Weg an den Bahnhof zu finden versuchen, wären wir schon mal nur froh, überhaupt einen Weg zu finden. Es könnte ja auch sein, dass wir uns in die Turnhalle begeben, von wo kein Weg zum Bahnhof führt. Oder dass wir von der Bahnhofstrasse zurück zur KSR gelangen:
 +
 +<figure graph_romis2>
 +[[http://magjac.com/graphviz-visual-editor/?dot=digraph%20Romanshorn%20%7B%0A%20%20%20%20rankdir%3DTB%3B%0A%09node%20%5Bshape%20%3D%20doublecircle%3B%20width%3D1%5D%3B%20KSR%20Bahnhof%3B%0A%09node%20%5Bshape%20%3D%20circle%3B%20width%3D1%3B%20fixedwidth%3Dtrue%5D%3B%0A%09KSR%20-%3E%20Turnhalle%20%5B%20label%20%3D%201%20%5D%3B%0A%09KSR%20-%3E%20Weitenzelgstr%20%5B%20label%20%3D%201%20%5D%3B%0A%09Weitenzelgstr%20-%3E%20Bahnhofstr%20%5B%20label%20%3D%208%20%5D%3B%0A%09KSR%20-%3E%20Sek%20%5B%20label%20%3D%202%20%5D%3B%0A%09Sek%20-%3E%20Bahnhofstr%20%5B%20label%20%3D%203%20%5D%3B%0A%09Bahnhofstr%20-%3E%20Bahnhof%20%5B%20label%20%3D%207%20%5D%3B%0A%09Bahnhofstr%20-%3E%20KSR%20%5B%20label%20%3D%204%20%5D%3B%0A%09Sek%20-%3E%20Hafenstrasse%20%5B%20label%20%3D%205%20%5D%3B%0A%09Hafenstrasse%20-%3E%20Bahnhof%20%5B%20label%20%3D%204%20%5D%3B%0A%09Sek%20-%3E%20Zelgstrasse%20%5B%20label%20%3D%207%20%5D%3B%0A%09Zelgstrasse%20-%3E%20Bahnhof%20%5B%20label%20%3D%205%20%5D%3B%0A%7D%0A|{{:talit:pasted:20220521-145117.png?400|Graph}}]]
 +<caption>Detaillierter Graph von der KSR zum Bahnhof</caption>
 +</figure>
  
  
-[[http://magjac.com/graphviz-visual-editor/?dot=digraph%20Romanshorn%20%7B%0A%20%20%20%20rankdir%3DTB%3B%0A%09node%20%5Bshape%20%3D%20doublecircle%3B%20width%3D1%5D%3B%20KSR%20Bahnhof%3B%0A%09node%20%5Bshape%20%3D%20circle%3B%20width%3D1%3B%20fixedwidth%3Dtrue%5D%3B%0A%09KSR%20-%3E%20Turnhalle%20%5B%20label%20%3D%201%20%5D%3B%0A%09KSR%20-%3E%20Weitenzelgstr%20%5B%20label%20%3D%201%20%5D%3B%0A%09Weitenzelgstr%20-%3E%20Bahnhofstr%20%5B%20label%20%3D%208%20%5D%3B%0A%09KSR%20-%3E%20Sek%20%5B%20label%20%3D%202%20%5D%3B%0A%09Sek%20-%3E%20Bahnhofstr%20%5B%20label%20%3D%203%20%5D%3B%0A%09Bahnhofstr%20-%3E%20Bahnhof%20%5B%20label%20%3D%207%20%5D%3B%0A%09Bahnhofstr%20-%3E%20KSR%20%5B%20label%20%3D%204%20%5D%3B%0A%09Sek%20-%3E%20Hafenstrasse%20%5B%20label%20%3D%205%20%5D%3B%0A%09Hafenstrasse%20-%3E%20Bahnhof%20%5B%20label%20%3D%204%20%5D%3B%0A%09Sek%20-%3E%20Zelgstrasse%20%5B%20label%20%3D%207%20%5D%3B%0A%09Zelgstrasse%20-%3E%20Bahnhof%20%5B%20label%20%3D%205%20%5D%3B%0A%7D%0A|{{:talit:pasted:20220521-145117.png?400}}]] 
 #### Aufgabe 2 #### Aufgabe 2
  
Zeile 254: Zeile 260:
 ++++ ++++
 </nodisp> </nodisp>
- 
 #### Aufgabe 4 - Graph Walk #### Aufgabe 4 - Graph Walk
  
Zeile 261: Zeile 266:
 **Aufgabe**: Schreibe eine Funktion `dfs(graph)`, die die Knoten eines Graphen mittels Tiefensuche ausgibt. **Aufgabe**: Schreibe eine Funktion `dfs(graph)`, die die Knoten eines Graphen mittels Tiefensuche ausgibt.
   * Die Ausgabe kann mit `print()` erfolgen oder eine Liste zurückgeben.   * Die Ausgabe kann mit `print()` erfolgen oder eine Liste zurückgeben.
-  * Herausforderung: schreibe eine [[https://en.wikipedia.org/wiki/Generator_(computer_programming)#Python|Generator-Funktion]] mit dem `yield` Keyword.+  * Herausforderung: schreibe eine [[talit:generators|Generator-Funktion]] mit dem `yield` Keyword.
  
 <nodisp 1> <nodisp 1>
Zeile 308: Zeile 313:
  
 Mit der Tiefensuche finden wir Pfade von A nach B in einem Graphen, aber vielleicht nehmen wir dabei grosse Umwege in Kauf, weil wir zuerst weit von A entfernte Knoten besuchen, bevor wir alle Nachbarn von A untersuchen. Wir möchten aber eine Möglichkeit haben, den Graphen *der Nähe nach* zu besuchen, also die Knoten in aufsteigender Distanz von A zu besuchen. Dieses Verfahren heisst **Breitensuche** (*Breadth First Search* - BFS). Mit der Tiefensuche finden wir Pfade von A nach B in einem Graphen, aber vielleicht nehmen wir dabei grosse Umwege in Kauf, weil wir zuerst weit von A entfernte Knoten besuchen, bevor wir alle Nachbarn von A untersuchen. Wir möchten aber eine Möglichkeit haben, den Graphen *der Nähe nach* zu besuchen, also die Knoten in aufsteigender Distanz von A zu besuchen. Dieses Verfahren heisst **Breitensuche** (*Breadth First Search* - BFS).
- 
 #### Aufgabe 5 #### Aufgabe 5
 Überlege dir, wie du vorgehen könntest, um zuerst die unmittelbaren Knoten des Starts zu besuchen, und nur allmählich weitere Kanten zu traversieren. Ignoriere die Kantengewichte dabei erst mal - du kannst von einem ungewichteten Graphen ausgehen. Überlege dir, wie du vorgehen könntest, um zuerst die unmittelbaren Knoten des Starts zu besuchen, und nur allmählich weitere Kanten zu traversieren. Ignoriere die Kantengewichte dabei erst mal - du kannst von einem ungewichteten Graphen ausgehen.
Zeile 325: Zeile 329:
     * Entdeckte, aber noch nicht besuchte Knoten in einer Liste: `candidates = [start]`     * Entdeckte, aber noch nicht besuchte Knoten in einer Liste: `candidates = [start]`
     * Noch unbekannte Knoten (brauchen wir uns nicht zu merken).     * Noch unbekannte Knoten (brauchen wir uns nicht zu merken).
-  * Solange `candidates` nicht leer ist, wird der vorderste Knoten `node` in `candidates` wird entfernt.+  * Solange `candidates` nicht leer ist, wird der vorderste Knoten `node` in `candidates` entfernt.
     * Falls `node` bereits in `visited` ist, gehen wir zum nächsten (er wurde mehrfach entdeckt über verschiedene Pfade).     * Falls `node` bereits in `visited` ist, gehen wir zum nächsten (er wurde mehrfach entdeckt über verschiedene Pfade).
     * Andernfalls: wird `node` zu `visited` hinzugefügt.     * Andernfalls: wird `node` zu `visited` hinzugefügt.
Zeile 370: Zeile 374:
 ++++ ++++
 </nodisp> </nodisp>
 +
  
 #### Aufgabe 6: Pfadsuche mit BFS #### Aufgabe 6: Pfadsuche mit BFS
Zeile 382: Zeile 387:
   * Zusätzlich merken wir uns:   * Zusätzlich merken wir uns:
     * alle besuchten Knoten (`visited`)     * alle besuchten Knoten (`visited`)
-    den Vorgänger-Knoten für jeden Knoten (`parent = {}`)+      Statt einem Set verwenden wir ein Dictionary für `visited`
 +      * Wir merken uns für jeden Knoten dessen ersten Vorgängerknoten, um daraus am Schluss den Pfad zu bauen.
 ++++ ++++
  
Zeile 407: Zeile 413:
     }     }
     return result     return result
- + 
-from collections import deque+
 def find_path_bfs(graph, start, end): def find_path_bfs(graph, start, end):
     """Finds a path from start to end using BFS. """     """Finds a path from start to end using BFS. """
-    # Deque: a double-ended list with efficient modifications at either end. +    candidates = [start] 
-    candidates = deque() +    visited = {start: None}
-    candidates.append(start) +
-    visited = {start+
-    parent = {}+
     while candidates:     while candidates:
-        next = candidates.popleft()+        next = candidates.pop(0)
         for neighbor in graph[next]:         for neighbor in graph[next]:
             if neighbor not in visited:             if neighbor not in visited:
-                visited.add(neighbor)+                visited[neighbor] = next
                 candidates.append(neighbor)                 candidates.append(neighbor)
-                parent[neighbor] = next 
                 if neighbor == end:                 if neighbor == end:
-                    return build_path_from_parents(graph, parent, start, end)+                    return build_path_from_parents(graph, visited, start, end)
     return None  # No path found     return None  # No path found
 </code> </code>
Zeile 484: Zeile 485:
  
 Der Algorithmus basiert auf dem folgenden Prinzip: Der Algorithmus basiert auf dem folgenden Prinzip:
-  * Die Kandidaten sind nach aufsteigender Distanz zum Startknoten sortiert. Für die effiziente Sortierung der Kandidaten benützen wir eine `PriorityQueue`.+  * Die Kandidaten sind nach aufsteigender Distanz zum Startknoten sortiert. 
 +    * Hier liegt der Unterschied zu BFS: statt die neu-entdeckten Kandidaten einfach hinten einzureihen, werden sie nach aufsteigender Distanz zum Start sortiert. 
 +    * Für die effiziente Sortierung der Kandidaten benützen wir eine [[wpde>Vorrangwarteschlange|PriorityQueue]].
   * Der vorderste Kandidat ist immer der nächste Knoten in aufsteigender Distanz von `start` her.   * Der vorderste Kandidat ist immer der nächste Knoten in aufsteigender Distanz von `start` her.
-  * Beweis: gäbe es einen Knoten `x` der näher bei `start` liegt, so wäre dessen Vorläufer-Knoten bereits besucht worden und die geringere Distanz von `x` wäre bereits bekannt geworden. +    * Beweis: gäbe es einen Knoten `x` der näher bei `start` liegt, so wäre dessen Vorläufer-Knoten bereits besucht worden und die geringere Distanz von `x` wäre bereits bekannt geworden. 
-  * Achtung: für alle weiteren Kandidaten stimmt die Sortierung noch nicht definitiv: möglicherweise gibt es einen kürzeren Pfad als den bekannten via einen weiter vorne liegenden Kandidaten!+    * Achtung: für alle weiteren Kandidaten stimmt die Sortierung noch nicht definitiv: möglicherweise gibt es einen kürzeren Pfad als den bekannten via einen weiter vorne liegenden Kandidaten, dessen Nachbarn noch nicht bekannt sind!
  
 <code python> <code python>
Zeile 579: Zeile 582:
 ++++ ++++
 </nodisp> </nodisp>
 +### Visualisierung
 +Mit Folium lassen sich die gefundenen Pfade hübsch visualiseren. Der Code für untenstehende Grafik findet sich auf [[https://github.com/tkilla77/ksr_talenta_graphs/blob/main/sbb.ipynb|github]].
 +
 +<figure shortest_path>
 +{{:talit:algorithmen:pasted:20250302-193146.png?nolink}}<caption>Pfad von Romanshorn nach Bern --- Rot: BFS, Grün: DFS, Blau: Dijkstra</caption>
 +</figure>
  • talit/algorithmen.1717393916.txt.gz
  • Zuletzt geändert: 2024-06-03 05:51
  • von hof