Iterative Tiefensuche

Die iterative Tiefensuche (englisch iterative deepening depth-first search, IDDFS) i​st ein Verfahren a​us der Informatik z​um Suchen e​ines Knotens i​n einem Graphen. Der Algorithmus kombiniert d​ie wünschenswerten Eigenschaften v​on Tiefensuche (geringer Speicherverbrauch) u​nd Breitensuche (Optimalität).

Allgemeines

Die iterative Tiefensuche ist wie die normale Tiefensuche eine uninformierte Suche. Sie funktioniert wie die Tiefensuche, vermeidet jedoch durch Begrenzung der Suchtiefe deren Nachteile bezüglich Vollständigkeit. Bei der iterativen Tiefensuche wird iterativ eine beschränkte Tiefensuche durchgeführt, und dabei das Level, bis zu welchem die Beschränkte Tiefensuche den Graphen erkundet, bei jeder Iteration um eins erhöht. Im ersten Schritt werden also alle Knoten, zu denen ein Pfad der Länge 0 führt, mittels Tiefensuche erkundet. Im nächsten Schritt werden dann alle Knoten, zu denen ein Pfad der Länge 1 führt, mittels Tiefensuche erkundet und so weiter. Hierdurch wird erreicht, dass Iterative Tiefensuche prinzipiell auf allen Graphen vollständig ist, da die Suche sich nun nicht mehr in einem endlos langen Pfad verlieren kann. Damit stellt die iterative Tiefensuche eine Kombination der Tiefen- und der Breitensuche dar. Sie hat einerseits den gleichen Speicherplatzverbrauch wie die normale Tiefensuche (im Arbeitsspeicher muss jeweils maximal ein kompletter Ast bis zur momentanen Iterationstiefe gespeichert werden), liefert aber bei monoton steigenden Pfadkosten, ebenso wie die Breitensuche, eine optimale Lösung. Da für jede neue Iteration auch der bereits durchlaufene Suchbaum komplett neu aufgebaut werden muss, ist die Laufzeit höher als bei normaler Tiefensuche. Da in einem Suchbaum aber jeweils der größte Teil der Knoten Blätter sind, ist dieser geringe Mehraufwand gegenüber den Vorteilen hinnehmbar.

Algorithmus (informell)

  1. Bestimme den Knoten, an dem die Suche beginnen soll
  2. Rufe Beschränkte Tiefensuche mit der aktuellen Suchtiefe auf
  3. Erhöhe die Suchtiefe um 1 und gehe zu Schritt 2

Algorithmus (formal)

Iterative Tiefensuche (Knoten, Ziel)
{
  IterationsTiefe := 0
  while (IterationsTiefe < unendlich)
  {
    Beschränkte_Tiefensuche (Knoten, Ziel, IterationsTiefe);
    IterationsTiefe := IterationsTiefe + 1;
  }
}

Algorithmusbeispiel: Erzeugen des Tiefensuchwaldes (iterativ)

Der folgende iterative Algorithmus erzeugt den Tiefensuchwald eines Graphen G mittels Setzen von Discovery- und Finishing-Times und Färben der Knoten. In Anlehnung an Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms, MIT Press, 2001, werden zunächst alle Knoten weiß gefärbt. Anschließend startet die Tiefensuche per Definition beim alphabetisch kleinsten Knoten und färbt diesen grau. Danach wird ein Stack verwendet, worin der bereits entdeckte Weg bis zu einem Knoten ohne weißen Nachbarn gespeichert wird. Alle Knoten im Stack sind grau. Der Stack wird abgetragen, bis einer der gespeicherten Knoten noch einen weiteren weißen Nachbarn hat oder der Stack leer ist. Damit wird das der Rekursion eigene Backtracking simuliert.

Die vorgefertigte Methode nextw(u) liefert für e​inen Knoten u d​en (per Definition alphabetisch kleinsten) weißen Nachbarn. Existiert k​ein solcher, liefert s​ie NULL bzw. FALSE.

for each v of G {		//Initialisierung: 
  col[v] = w;			//Alle Knoten weiß färben und 
  pi[v] = null;			//Vorgänger auf null setzen
}
time=0;				
S=0;				//Stack S initialisieren
 
for each u of G {		//für alle weißen Knoten u
   if (col[u]==w) {		
     time++;			//Zeitzähler erhöhen
     col[u] = g;		//Aktuellen Knoten grau färben
     d[u] = time;		//Entdeckzeit setzen
     push(S, u);		//Aktuellen Knoten auf Stack
     while (S!=0) {		//Solange Stack belegt ist
       time++;			//Zeitzähler erhöhen
       v = nextw(u);	
       if (v!=null) {		//wenn nächster weißer Nachbar
         col[v] = g;		//v grau färben
         d[v] = time;		//Entdeckzeit setzen
         pi[v] = u;		//Vorgänger setzen
         if (nextw(v)!=null) 
           push(S, v);
         u=v;			//Aktueller Knoten ist v
       } else {			//wenn v NULL
         col[u] = s;		//Aktuellen Knoten schwarz färben
         f[u] = time;		//Finishing-Time setzen
         if (S!=0) 
           u = pop(S);		//neuer aktueller Knoten von Stack
         if (col[u]==g)
           push(S,u);		//Solange Knoten noch nicht Schwarz, wieder auf den Stack
       }
     }
   }
 }
nextw(u) {
  for each node of adj[u] {                                      
    if col[node]==w 
      return node;
    else                          
      return null;
  }
}

Eigenschaften

Speicherplatzverbrauch

Da intern a​uf Tiefensuche zurückgegriffen wird, i​st der Speicherplatzbedarf ähnlich d​em der normalen Tiefensuche.

Laufzeit

Da im schlimmsten Fall alle möglichen Pfade zu allen möglichen Knoten betrachtet werden müssen, beträgt die Laufzeit von Iterativer Tiefensuche , wobei für die Anzahl der Knoten und für die Anzahl der Kanten im Graph steht.

Vollständigkeit

Da s​ich Iterative Tiefensuche w​eder in unendlich langen Pfaden n​och in Zyklen verlieren kann, i​st der Algorithmus vollständig.

Optimalität

Iterative Tiefensuche i​st optimal, f​alls alle Pfadkosten äquivalent sind, d​a Tiefensuche i​n diesem Fall d​en kürzesten Pfad z​u einem Ziel findet. Sind d​ie Pfadkosten jedoch n​icht äquivalent, s​o kann e​s wie b​ei der Breitensuche d​azu kommen, d​ass ein suboptimaler Pfad gewählt wird.

Literatur

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. The authors of the article are listed here. Additional terms may apply for the media files, click on images to show image meta data.