Tiefensuche (Depth-First Search) Robert Hilbrich
[email protected]
1
Gliederung 1. Einführung 2. Tiefensuche, der Algorithmus
2.1 Modellierung der Arbeitsumgebung 2.2 Programmablauf
3. Korrektheit
3.1 Partielle Korrektheit 3.2 Totale Korrektheit
4. Einordnung der Tiefensuche 2
1. Einführung
Adventure: „Indiana Jones and the Fate of Atlantis“ (Fiktive)
Spielsituation:
• Indy gerät in ein Labyrinth • sucht Ausgang (z.B. Sophia) • Verfügbare Gegenstände: • Peitsche • Revolver • (beliebig lange) rote Schnur Wie geht Indy möglichst systematisch vor?
3
1. Einführung
„Indiana Jones And The Fate of Atlantis“ systematische Vorgehensweise: • roten Faden spannen à bereits „gesehene“ Wege markieren • Wenn „Sackgasse“ à zurück zur letzten „ungesehenen“ Gabelung è Vermeidung „doppelter“ Wege 4
1. Einführung
Heutige Bedeutung in der Informatik abstrakt: • bekanntes Suchverfahren für Graphenprobleme z.B.: • Ist der Graph verbunden? • Wenn nicht, was sind die Zusammenhangskomponenten? • Existiert ein Kreisschluss im Graphen? konkret: • Routenplaner • Roboter Steuerungslogik • Spiele – Logik • Prolog 5
2. Tiefensuche, der Algorithmus
6
2.1 Modellierung der Arbeitsumgebung
Tiefensuche arbeitet mit Graphen • •
Sei ein (ungerichteter) Graph G mit V Knoten und E Kanten gegeben alle Knoten seien eindeutig nummeriert (0,1,2,...)
Modellierung von G: 1. Knoteninformationen 2. Kanteninformationen
7
2.1 Modellierung der Arbeitsumgebung
1. Feld der Länge V (=maxV) für die Knoten VAR val: array[0..maxV-1]of Integer; • •
Index = Knotennummer in G Eintrag = Markierung des Knoten, durch: •
i-te Knoten noch nicht „besucht“: val[i] = 0
•
j-te Knoten schon „besucht“: val[j] > 0
8
2.1 Modellierung der Arbeitsumgebung
2. Adjazenzliste zur Speicherung der Kanten • • •
Array der Länge v von einfach verketteten Listen Index des Array = Knotennummer Listen Elemente = direkte Nachbarn im Graphen Array Listen 0
1
2
1
0
2
2
0
1
3
2
Graph 1 2 3
0 3 9
2.2 Programmablauf
Tiefensuche – der Algorithmus PROGRAM tiefensuche; VAR id, k val
: INTEGER; : array [1..V-1] of INTEGER;
PROCEDURE visit(k : INTEGER); VAR t : Zeiger; BEGIN id := id+1; val[k] := id; t := adj[k]; WHILE t != NULL DO BEGIN IF val[t^.v] = 0 THEN visit(t^.v); t := t^.next; END; END; BEGIN
{ HAUPTPROGRAMM } id := 0; FOR k := 0 TO (V-1) DO val[k] := 0; FOR k := 0 TO (V-1) DO IF val[k] = 0 THEN visit(k);
END; 10
2.2 Programmablauf
Tiefensuche – der Algorithmus
PROGRAM tiefensuche; VAR id, k : INTEGER; val : array [0..V-1] of INTEGER; PROCEDURE visit(k : INTEGER); VAR t : Zeiger; BEGIN id := id+1; val[k] := id; t := adj[k]; WHILE t != NULL DO BEGIN IF val[t^.v] = 0 THEN visit(t^.v); t := t^.next; END; END; BEGIN id := FOR k FOR k IF END;
0; := 0 TO (V-1) DO val[k] := 0; := 0 TO (V-1) DO val[k] = 0 THEN visit(k);
id : „entdeckte“ Knoten k
: aktueller Knoten
visit: sucht rekursiv alle Knoten einer Zusammenhangskomponente t: Zeiger auf Nachbarknoten von k val[k]: Eintrag im Knotenfeld (Markierung) adj[k]: Adjazenzliste (Nachfolger) 11
2.2 Programmablauf
Beispiel: Graph G und zugehörige Adjazenzliste
0 3
2
4 6
7 1
5
0
2
3
1
5
2
0
3
0
4
4
3
6
5
1
8
6
4
7
4
8
5
7
8 12
2.2 Programmablauf
Initialisierung Graph G, Adjazenzliste und val[0..maxV-1] Feld FOR k := 0 TO V-1 DO val[k] := 0;
Index 0 0 1 3 2 2 3 4 4 6 7 5 6 1 5 7 8 8 Graph
2 5 0 0 3 1 4 4 5
3
4 6 8
Index 0 1 2 3 4 5 7 6 7 8
Eintrag 0 0 0 0 0 0 0 0 0 val[k]
Adjazenzliste 13
2.2 Programmablauf
Start im Hauptprogramm FOR k := 0 TO V-1 DO IF val[k] = 0 THEN visit(k);
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0
14
2.2 Programmablauf
visit(0) à visit(2)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 0 0 0 0 0 0 0
15
2.2 Programmablauf
visit(2) à check(0)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 0 0 0 0 0 0
16
2.2 Programmablauf
visit(0) à visit(3)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 0 0 0 0 0 0
17
2.2 Programmablauf
visit(3) à check(0)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 0 0 0 0 0
18
2.2 Programmablauf
visit(3) à visit(4)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 0 0 0 0 0
19
2.2 Programmablauf
visit(4) à check(3)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 4 0 0 0 0
20
2.2 Programmablauf
visit(4) à visit(6)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 4 0 0 0 0
21
2.2 Programmablauf
visit(6) à check(4)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 4 0 5 0 0
22
2.2 Programmablauf
visit(4) à visit(7)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 4 0 5 0 0
23
2.2 Programmablauf
visit(7) à check(4)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 4 0 5 6 0
24
2.2 Programmablauf
Hauptprogramm à visit(1)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 0 2 3 4 0 5 6 0
25
2.2 Programmablauf
visit(1) à visit(5)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 7 2 3 4 0 5 6 0
26
2.2 Programmablauf
visit(5) à check(1)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 7 2 3 4 8 5 6 0
27
2.2 Programmablauf
visit(5) à visit(8)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 7 2 3 4 8 5 6 0
28
2.2 Programmablauf
visit(8) à check(5)
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 7 2 3 4 8 5 6 9
29
2.2 Programmablauf
Ende der FOR – Schleife, da k = V FOR k := 0 TO (V-1) DO IF val[k] = 0 THEN visit(k);
0 3
2
4 6 1
7 5 8
0 1 2 3 4 5 6 7 8
2 5 0 0 3 1 4 4 5
3
4 6 8
7
0 1 2 3 4 5 6 7 8
1 7 2 3 4 8 5 6 9
30
2.2 Programmablauf
Zusammenfassung • Tiefensuche durchsucht Graphen
• Stack (Rekursion) • „Backtracking“ • TS stößt immer zuerst in die maximale Tiefe vor
31
3. Korrektheit
32
3.1 Partielle Korrektheit
Partielle Korrektheit mit Hoare Kalkül • sehr umfangreich (2 A4 Seiten) • langwierig • sich wiederholend à monoton
à Beschränkung auf Interessantes • Anfangs- und Endbedingungen • Schleifeninvarianten • Rekursion
33
3.1 Partielle Korrektheit
Hoare Kalkül und Nassi-Schneidermann Diagramme
{P}
{I}
Anweisung
B
{Q}
{ I und B} Anweisung 1 Anweisung 2 {I} { I und nicht (B) }
34
3.1 Partielle Korrektheit
Anfangs- und Endbedingungen • V = Anzahl aller Knoten im Graphen • V1 = Anzahl aller markierten Knoten im Graphen • V2 = Anzahl aller nicht markierten Knoten in der aktuellen Zusammenhangskomponente (ZK) • V3 = Anzahl aller nicht markierten Knoten, die nicht in der aktuellen ZK sind • k = aktueller Knoten
{ P } V=V1+V2+V3 und V>0 Hauptprogramm { Q } V=V1 und V2=0 und V3=0 und k=V 35
3.1 Partielle Korrektheit
Anfangs- und Endbedingungen • val[k] = 0 : unbesichtigter Knoten • t^.v : Nachbarknoten von k in Adjazenzliste • (t^.next).v : NachbarNachbarknoten von k in Adjazenzliste
P: val[k] = 0 PROCEDURE visit(k) Q: nicht(val[k] = 0) und nicht(val[t^.v] = 0) und nicht(val[(t^.next)^.v] = 0) und nicht ...
36
3.1 Partielle Korrektheit
Invarianten im Hauptprogramm (FOR Schleifen durch WHILE ersetzt)
FOR k := 0 TO (V-1) DO IF val[k] = 0 THEN visit(k);
{ I }: V = V1 + V2 + V3 und V-k >= 0 Wiederhole, solange wie k = 0 und nicht (k V
40
3.2 Totale Korrektheit
Totale Korrektheit = Terminierung der WHILE Schleifen Prozedur VISIT Zusätzliche Funktionen nötig, da Terminierungsfunktion f(t) nach N abbildet. LE sei ein Listenelement nachfolger(LE) := Anzahl der Nachfolger + 1 f(t) = nachfolger(t) f(t) = 0
, falls t != NULL , falls t = NULL
41
4. Einordnung der Tiefensuche
42
4. Einordnung der Tiefensuche
Tiefensuche = ein typischer Vertreter von Suchalgorithmen weitere Vertreter : • Breitensuche • Allgemeine Kostensuche • Tiefenbeschränkte Suche • bidirektionale Suche • „Gierige“ Suche • „Hill – Climbing“ Suche • [...] Informationen:
http://wwwbrauer.in.tum.de/seminare/web/WS0001/vortrag01.html 43
4. Einordnung der Tiefensuche
FAZIT • moderater Speicherverbrauch • Keine Tiefensuche bei großen (infiniten) Tiefen • „Tiefenbeschränkte Suche“ als Alternative
44
Quellen • http://www.informatik.uni-stuttgart.de/ifi/bs/lehre/ei1/1999/htm/graph3.htm • Gerald Futschek; Programmentwicklung und Verifikation; Springer-Verlag Wien New-York; 1989; • Robert Sedgewick; Algorithms in Java; Addison Wesley; 2002 • http://www.informatik.uni-bremen.de/~visser/lectures/ki-1_WS9900/slides/kap_3_suche.pdf • http://wwwbrauer.in.tum.de/seminare/web/WS0001/vortrag01.html • http://www.informatik.uni-stuttgart.de/ifi/bs/lehre/ei1/1999/htm/graph3.htm
45
Abschluss
„Indiana Jones – Der Entdecker der Tiefensuche?“ • Indys Vorgehen entspricht dem Ablauf des Algorithmus der Tiefensuche • Dennoch, Indiana Jones ist nicht der Entdecker ... „Die Tiefensuche ist schon aus dem Altertum und aus der griechischen Sage bekannt unter dem Namen Labyrinth-Suche. Dieser bezieht sich auf die Erzählung von dem griechischen Helden Theseus, der nach Kreta reiste, um dort ein Untier namens Minotauros zu erlegen, das dort in einem unterirdischen Höhlensystem, genannt Labyrinth, sein Unwesen trieb. [...] jedenfalls fand Theseus den Minotauros mittels Tiefensuche, und als Markierungshilfsmittel verwendete er das Wollknäuel aus dem Strickzeug der Königstochter Ariadne, [...]“ 46