Sie sind auf Seite 1von 46

Tiefensuche

(Depth-First Search)
Robert Hilbrich
hilbrich@cpc4u.de

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 Graph


0 1 2 1
1 0 2 2

2 0 1 3 0

3 2 3

9
2.2 Programmablauf
Tiefensuche – der Algorithmus
PROGRAM tiefensuche;
VAR id, k : INTEGER;
val : 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; id : „entdeckte“ Knoten
VAR id, k : INTEGER;
val : array [0..V-1] of INTEGER; k : aktueller Knoten
PROCEDURE visit(k : INTEGER); visit:
VAR t : Zeiger;
BEGIN sucht rekursiv alle Knoten
id := id+1; einer
Zusammenhangskomponente
val[k] := id;
t := adj[k];
WHILE t != NULL DO BEGIN
IF val[t^.v] = 0 THEN visit(t^.v); t:
t := t^.next; Zeiger auf Nachbarknoten
von k
END;
END;

BEGIN val[k]:
id := 0; Eintrag im Knotenfeld
(Markierung)
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; adj[k]:
Adjazenzliste (Nachfolger)
11
2.2 Programmablauf

Beispiel: Graph G und zugehörige Adjazenzliste

0 2 3
1 5
0 2 0
3 2 3 0 4

4 4 3 6 7

6 7 5 1 8
6 4
1 5
7 4
8
8 5
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 Index Eintrag


0 0 2 3 0 0
1 5 1 0
3 2 2 0
2 0 3 0
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0 val[k]
1 5 7 4
8 Graph 8 5 Adjazenzliste
13
2.2 Programmablauf

Start im Hauptprogramm

FOR k := 0 TO V-1 DO IF val[k] = 0 THEN visit(k);

0 0 2 3 0 0
1 5 1 0
3 2 2 0
2 0 3 0
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

14
2.2 Programmablauf

visit(0) à visit(2)

0 0 2 3 0 1
5 1 0
3 2 1 2 0
2 0 3 0
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

15
2.2 Programmablauf

visit(2) à check(0)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 0
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

16
2.2 Programmablauf

visit(0) à visit(3)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 0
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

17
2.2 Programmablauf

visit(3) à check(0)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

18
2.2 Programmablauf

visit(3) à visit(4)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 0
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

19
2.2 Programmablauf

visit(4) à check(3)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

20
2.2 Programmablauf

visit(4) à visit(6)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 0
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

21
2.2 Programmablauf

visit(6) à check(4)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 5
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

22
2.2 Programmablauf

visit(4) à visit(7)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 5
5 1 8
7 0
6 4 8 0
1 5 7 4
8 8 5

23
2.2 Programmablauf

visit(7) à check(4)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 5
5 1 8
7 6
6 4 8 0
1 5 7 4
8 8 5

24
2.2 Programmablauf

Hauptprogramm à visit(1)

0 0 2 3 0 1
5 1 0
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 5
5 1 8
7 6
6 4 8 0
1 5 7 4
8 8 5

25
2.2 Programmablauf

visit(1) à visit(5)

0 0 2 3 0 1
5 1 7
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 0
6 7 6 5
5 1 8
7 6
6 4 8 0
1 5 7 4
8 8 5

26
2.2 Programmablauf

visit(5) à check(1)

0 0 2 3 0 1
5 1 7
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 8
6 7 6 5
5 1 8
7 6
6 4 8 0
1 5 7 4
8 8 5

27
2.2 Programmablauf

visit(5) à visit(8)

0 0 2 3 0 1
5 1 7
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 8
6 7 6 5
5 1 8
7 6
6 4 8 0
1 5 7 4
8 8 5

28
2.2 Programmablauf

visit(8) à check(5)

0 0 2 3 0 1
5 1 7
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 8
6 7 6 5
5 1 8
7 6
6 4 8 9
1 5 7 4
8 8 5

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 0 2 3 0 1
5 1 7
3 2 1 2 2
2 0 3 3
4 3 0 4 4 4
4 3 6 7 5 8
6 7 6 5
5 1 8
7 6
6 4 8 9
1 5 7 4
8 8 5

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 <= V


{ I } V = V1 + V2 + V3
und { B } k <= V
Anweisung(en)

{ I } V = V1 + V2 + V3 und V - k >= 0
{ I } V = V1 + V2 + V3 und V-k >= 0
und nicht (k <= V)

37
3.1 Partielle Korrektheit

Invarianten in VISIT
WHILE t != NULL DO BEGIN
IF val[t^.v] = 0 THEN visit(t^.v);
t := t^.next;
END;

{ I } t = NULL oder t^.next = NULL oder


(t^.next)^.next = NULL oder ...
Wiederhole solange wie nicht (t = NULL)
{ I und B} (t = NULL oder t^.next = NULL oder
(t^.next)^.next = NULL oder ...) und nicht (t = NULL)
Anweisung(en)
{ I } t = NULL oder t^.next = NULL oder (t^.next)^.next =
NULL oder ...
{ I und nicht B} (t = NULL oder t^.next = NULL oder
(t^.next)^.next = NULL oder ...) und t = NULL

38
3.1 Partielle Korrektheit

Rekursion in VISIT
IF val[t^.v] = 0 THEN visit(t^.v);

• Nach Hoare gilt ... (Beweis: über Induktion, à K. Schmidt, ThI 1)

val[t^.v] = 0

visit(t^.v)

nicht(val[t^.v] = 0) und
nicht(val[(t^.next)^.v] = 0) und nicht ...

39
3.2 Totale Korrektheit

Totale Korrektheit =
Terminierung der WHILE Schleifen
Hauptprogramm:

Für die Terminierungsfunktion f(V,k) gilt:

f(V,k) = V – k + 1 , denn:

0 = f(V,k) à k = V + 1 à 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) , falls t != NULL


f(t) = 0 , 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_WS99-
00/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