• Keine Ergebnisse gefunden

Algorithmen und Datenstrukturen C2. Graphenexploration: Anwendungen Gabriele R¨oger

N/A
N/A
Protected

Academic year: 2022

Aktie "Algorithmen und Datenstrukturen C2. Graphenexploration: Anwendungen Gabriele R¨oger"

Copied!
39
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Algorithmen und Datenstrukturen

C2. Graphenexploration: Anwendungen

Gabriele R¨ oger

Universit¨ at Basel

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 1 / 39

(2)

Algorithmen und Datenstrukturen

— C2. Graphenexploration: Anwendungen

C2.1 Erreichbarkeit

C2.2 K¨ urzeste Pfade

C2.3 Azyklische Graphen

C2.4 Zusammenhang

C2.5 Zusammenfassung

(3)

Erinnerung: Graphenexploration

I Aufgabe: Gegeben einen Knoten v , besuche alle Knoten, die von v aus erreichbar sind.

I Wird oft als Teil anderer Graphenalgorithmen ben¨ otigt.

I Tiefensuche: erst einmal m¨ oglichst tief in den Graphen (weit weg von v)

I Breitensuche: erst alle Nachbarn, dann Nachbarn der Nachbarn, . . .

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 3 / 39

(4)

Graphen: ¨ Ubersicht

Graphen

Repr¨ asentation Exploration Exploration:

Anwendungen

Erreichbarkeit K¨ urzeste

Pfade Zykelerkennung

Topologische Sortierung Zusammenhangs-

komponenten Minimale

Spannb¨ aume K¨ urzeste

Pfade

Andere

Graphenprobleme

(5)

C2.1 Erreichbarkeit

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 5 / 39

(6)

Graphen: ¨ Ubersicht

Graphen

Repr¨ asentation Exploration Exploration:

Anwendungen

Erreichbarkeit K¨ urzeste

Pfade Zykelerkennung

Topologische Sortierung Zusammenhangs-

komponenten Minimale

Spannb¨ aume K¨ urzeste

Pfade

Andere

Graphenprobleme

(7)

Mark-and-Sweep-Speicherbereinigung

Ziel: Gib Speicherplatz frei, der von nicht mehr zugreifbaren Ziel: Objekten belegt wird.

I Gerichteter Graph: Objekte als Knoten, Referenzen auf Objekte als Kanten

I Ein Bit pro Objekt f¨ ur Markierung in Speicherbereinigung I Mark: Markiere in regelm¨ assigen Abst¨ anden alle erreichbaren

Objekte.

I Sweep: Gib alle nicht markierten Objekte frei.

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 7 / 39

(8)

Zauberstab in Bildbearbeitung

(9)

C2.2 K¨ urzeste Pfade

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 9 / 39

(10)

Graphen: ¨ Ubersicht

Graphen

Repr¨ asentation Exploration Exploration:

Anwendungen

Erreichbarkeit K¨ urzeste

Pfade Zykelerkennung

Topologische Sortierung Zusammenhangs-

komponenten Minimale

Spannb¨ aume K¨ urzeste

Pfade

Andere

Graphenprobleme

(11)

K¨ urzeste Pfade: Idee

I Breitensuche besucht die Knoten mit aufsteigendem (minimalen) Abstand vom Startknoten.

I Erster Besuch eines Knoten passiert auf k¨ urzestem Pfad.

I Idee: Verwende Pfad aus induzierten Suchbaum

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 11 / 39

(12)

Jupyter-Notebook

Jupyter-Notebook: graph exploration applications.ipynb

(13)

K¨ urzeste-Pfade-Problem

K¨ urzeste-Pfade-Problem mit einem Startknoten I Gegeben: Graph und Startknoten s

I Anfrage f¨ ur Knoten v

I Gibt es Pfad von s nach v ?

I Wenn ja, was ist der k¨ urzeste Pfad?

I Engl. single-source shortest paths, SSSP

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 13 / 39

(14)

K¨ urzeste Pfade: Algorithmus

1

class SingleSourceShortestPaths:

2

def __init__(self, graph, start_node):

3

self.predecessor = [None] * graph.no_nodes()

4

self.predecessor[start_node] = start_node

5

6

# precompute predecessors with breadth-first search with

7

# self.predecessors used for detecting visited nodes

8

queue = deque()

9

queue.append(start_node)

10

while queue:

11

v = queue.popleft()

12

for s in graph.successors(v):

13

if self.predecessor[s] is None:

14

self.predecessor[s] = v

15

queue.append(s)

16

...

Im Prinzip wie gehabt

(nur als Klasse)

(15)

K¨ urzeste Pfade: Algorithmus (Fortsetzung)

19

def has_path_to(self, node):

20

return self.predecessor[node] is not None

21

22

def get_path_to(self, node):

23

if not self.has_path_to(node):

24

return None

25

if self.predecessor[node] == node: # start node

26

return [node]

27

pre = self.predecessor[node]

28

path = self.get_path_to(pre)

29

path.append(node)

30

return path

Laufzeit?

Sp¨ ater: K¨ urzeste Pfade mit Kantengewichten

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 15 / 39

(16)

C2.3 Azyklische Graphen

(17)

Graphen: ¨ Ubersicht

Graphen

Repr¨ asentation Exploration Exploration:

Anwendungen

Erreichbarkeit K¨ urzeste

Pfade Zykelerkennung

Topologische Sortierung Zusammenhangs-

komponenten Minimale

Spannb¨ aume K¨ urzeste

Pfade Andere Graphenprobleme

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 17 / 39

(18)

Erkennung von azyklischen Graphen

Definition (Gerichteter, azyklischer Graph)

Ein gerichteter, azyklischer Graph (directed acyclic graph, DAG) ist ein gerichteter Graph, der keine gerichteten Zyklen enth¨ alt.

Aufgabe: Entscheide, ob ein gerichteter Graph

Aufgabe: einen Zyklus enth¨ alt. Falls ja, gib einen Zyklus aus.

(19)

Kriterium f¨ ur Zykelfreiheit

vo rw ¨arts

r¨uckw

¨arts seit w¨arts

Induzierter Suchbaum einer Tiefensuche (orange) und m¨ ogliche andere Kanten

Der (erreichbare Teil-) Graph ist genau dann azyklisch, wenn keine R¨ uckw¨ artskante existiert.

Idee: Merke dir Knoten auf aktuellem Pfad in Tiefensuche

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 19 / 39

(20)

Zykeltest: Algorithmus

1

class DirectedCycle:

2

def __init__(self, graph):

3

self.predecessor = [None] * graph.no_nodes()

4

self.on_current_path = [False] * graph.no_nodes()

5

self.cycle = None

6

for node in range(graph.no_nodes()):

7

if self.has_cycle():

8

break

9

if self.predecessor[node] is None:

10

self.predecessor[node] = node

11

self.dfs(graph, node)

12

13

def has_cycle(self):

14

return self.cycle is not None

Wiederholte Tiefen-

suchen, so dass am

Ende alle Knoten

besucht wurden

(21)

Zykeltest: Algorithmus (Fortsetzung)

16

def dfs(self, graph, node):

17

self.on_current_path[node] = True

18

for s in graph.successors(node):

19

if self.has_cycle():

20

return

21

if self.on_current_path[s]:

22

self.predecessor[s] = node

23

self.extract_cycle(s)

24

if self.predecessor[s] is None:

25

self.predecessor[s] = node

26

self.dfs(graph, s)

27

self.on_current_path[node] = False

Aktualisiere, ob Knoten auf aktuellem Pfad ist.

Brich ab, wenn irgendwo Zyklus gefunden.

Zyklus gefunden

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 21 / 39

(22)

Zykeltest: Algorithmus (Fortsetzung)

Bei Aufruf von extract cycle liegt node auf einem Zyklus in self.predecessor.

29

def extract_cycle(self, node):

30

self.cycle = deque()

31

current = node

32

self.cycle.appendleft(current)

33

while True:

34

current = self.predecessor[current]

35

self.cycle.appendleft(current)

36

if current == node:

37

return

(23)

Jupyter-Notebook

Jupyter-Notebook: graph exploration applications.ipynb

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 23 / 39

(24)

Graphen: ¨ Ubersicht

Graphen

Repr¨ asentation Exploration Exploration:

Anwendungen

Erreichbarkeit K¨ urzeste

Pfade Zykelerkennung

Topologische Sortierung Zusammenhangs-

komponenten Minimale

Spannb¨ aume K¨ urzeste

Pfade

Andere

Graphenprobleme

(25)

Topologische Sortierung

Definition

Eine topologische Sortierung eines azyklischen, gerichteten Graphen G = (V , E ), ist eine Nummerierung no : V → N der Knoten, so dass f¨ ur jede Kante (u , v) gilt, dass no(u) < no(v ).

Zum Beispiel relevant f¨ ur Ablaufplanung:

Kante (u, v) dr¨ uckt aus, dass u vor v

” erledigt“ werden muss.

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 25 / 39

(26)

Topologische Sortierung: Illustration

0 1

2 3

4 5 6

4 6 1 3 0 2 5

1

2

3

4

5

6

7

(27)

Topologische Sortierung: Algorithmus

Theorem

F¨ ur den erreichbaren Teilgraphen eines azyklischenen Graphen ist die umgekehrte Depth-First-Postorder-Knotenreihenfolge eine topologische Sortierung.

Algorithmus:

I Folge von Tiefensuchen-Aufrufen (f¨ ur bisher unbesuchte Knoten) bis alle Knoten besucht.

I Speichere jeweils umgekehrte Postorderreihenfolge P i f¨ ur i-te Suche

I Sei k Anzahl der Suchen. Dann ergibt die Aneinanderreihung von P k , . . . , P 1 eine topologische Sortierung.

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 27 / 39

(28)

C2.4 Zusammenhang

(29)

Graphen: ¨ Ubersicht

Graphen

Repr¨ asentation Exploration Exploration:

Anwendungen

Erreichbarkeit K¨ urzeste

Pfade Zykelerkennung

Topologische Sortierung Zusammenhangs-

komponenten Minimale

Spannb¨ aume K¨ urzeste

Pfade Andere Graphenprobleme

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 29 / 39

(30)

Zusammenhangskomponenten ungerichteter Graphen

Ungerichteter Graph

I Zwei Knoten u und v sind in der gleichen Zusammenhangskomponente, wenn es einen Pfad zwischen u und v gibt.

0 1

2 3

4

5

6

7 8

9

(31)

Zusammenhangskomponenten: Interface

Wir m¨ ochten folgendes Interface implementieren:

1

class ConnectedComponents:

2

# Vorverarbeitender Konstruktor

3

def __init__(graph: UndirectedGraph) -> None

4

5

# Sind Knoten node1 und node2 verbunden?

6

def connected(node1: int, node2: int) -> bool

7

8

# Anzahl der Zusammenhangskomponenten

9

def count() -> int

10

11

# Komponentenbezeichner f¨ ur node

12

# (zwischen 0 und count()-1)

13

def id(node: int) -> int

Idee: Folge von Graphexplorationen bis alle Knoten besucht sind.

Idee: ID eines Knoten entspricht Iteration, in der er besucht wurde

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 31 / 39

(32)

Zusammenhangskomponenten: Algorithmus

1

class ConnectedComponents:

2

def __init__(self, graph):

3

self.id = [None] * graph.no_nodes()

4

self.curr_id = 0

5

visited = [False] * graph.no_nodes()

6

for node in range(graph.no_nodes()):

7

if not visited[node]:

8

self.dfs(graph, node, visited)

9

self.curr_id += 1

10

11

def dfs(self, graph, node, visited):

12

if visited[node]:

13

return

14

visited[node] = True

15

self.id[node] = self.curr_id

16

for n in graph.neighbours(node):

17

self.dfs(graph, n, visited)

(33)

Jupyter-Notebook

Jupyter-Notebook: graph exploration applications.ipynb

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 33 / 39

(34)

Zusammenhangskomponenten gerichteter Graphen

Gerichteter Graph G

I Ignoriert man die Richtung der Kanten, ist jede

Zusammenhangskomponente des resultierenden ungerichteten Graphen eine schwache Zusammenhangskomponente von G . I G ist stark zusammenh¨ angend, wenn von jedem Knoten zu

jedem anderen Knoten ein gerichteter Pfad existiert.

I Eine starke Zusammenhangskomponente von G ist ein

maximal grosser Teilgraph, der stark zusammenh¨ angend ist.

(35)

Starke Zusammenhangskomponenten

0 1

2 3

4

5

6

7 8

9

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 35 / 39

(36)

Starke Zusammenhangskomponenten

Kosaraju-Algorithmus

I Gegeben Graph G = (V , E), berechne zun¨ achst ein umgekehrte Postorderreihenfolge P (f¨ ur alle Knoten) des Graphen G R = (V , {(v, u) | (u, v) ∈ E }) (alle Kanten umgedreht).

I F¨ uhre eine Folge von Explorationen in G aus.

W¨ ahle dabei als n¨ achsten Startknoten jeweils den ersten noch unbesuchten Knoten in P .

I Alle Knoten, die innerhalb einer Exploration erreicht werden,

sind in der gleichen starken Zusammenhangskomponente.

(37)

Jupyter-Notebook

Jupyter-Notebook: graph exploration applications.ipynb

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 37 / 39

(38)

C2.5 Zusammenfassung

(39)

Zusammenfassung

Wir haben eine Reihe von Anwendungen der Graphenexploration betrachtet:

I Erreichbarkeit I K¨ urzeste Pfade I Zykelerkennung

I Topologische Sortierung I Zusammenhangskomponenten

G. R¨oger (Universit¨at Basel) Algorithmen und Datenstrukturen 39 / 39

Referenzen

ÄHNLICHE DOKUMENTE

I Invariante 2: Zum Ende jedes Durchlaufs der ¨ ausseren Schleife ist keines der Elemente an den Positionen ≤ i gr¨ osser als ein Element an einer Position &gt; i. I Korrektheit

G ist stark zusammenh¨ angend, wenn von jedem Knoten zu jedem anderen Knoten ein gerichteter Pfad existiert. Eine starke Zusammenhangskomponente von G ist ein maximal grosser

Anf¨ anglich liegt jeder Knoten (alleine) in seiner eigenen Zusammenhangskomponente (insgesamt n St¨ uck).. Aktualisiere das Array bei jedem Aufruf

Gibt es mehrere Kanten, die einen noch nicht enthaltenen Knoten mit dem Baum verbinden, k¨ onnen nur die mit minimalem Gewicht gew¨ ahlt werden. Es reicht, jeweils nur eine solche

C4.1 Minimale Spannb¨ aume C4.2 Generischer Algorithmus C4.3 Graphenrepr¨ asentation C4.4 Kruskals Algorithmus C4.5 Prims Algorithmus... Minimale Spannb¨ aume Minimale

Da der Graph keine Zyklen mit negativen Gesamtkosten enth¨ alt, kann kein Pfad von s zu s negative Kosten haben. Die Kosten des leeren Pfades sind damit optimal und distance[s]

I distance[u]: L¨ ange des k¨ urzesten bekannten Pfades zu u I distance[v]: L¨ ange des k¨ urzesten bekannten Pfades zu v I parent[v]: Vorg¨ anger in letzter Kante. des k¨

I Liegt ein Knoten eines solchen Zyklus auf einem Pfad von s nach v, k¨ onnen wir Pfade finden, deren Gewicht niedriger als jeder gegebene Wert ist. → kein korrekt