it-swarm.com.de

Warum DFS und nicht BFS zum Finden von Zyklen in Diagrammen

Überwiegend wird DFS verwendet, um einen Zyklus in Diagrammen und nicht in BFS zu finden. Irgendwelche Gründe? Beide können feststellen, ob ein Knoten bereits beim Durchlaufen des Baums/Graphen besucht wurde.

70
badcompany

Die Tiefensuche ist speichereffizienter als die Breitensuche, da Sie früher zurückverfolgen können. Es ist auch einfacher zu implementieren, wenn Sie den Aufrufstapel verwenden, dies setzt jedoch voraus, dass der längste Pfad den Stapel nicht überläuft.

Auch wenn Ihr Graph gerichtet ist, müssen Sie sich nicht nur erinnern, ob Sie einen Knoten besucht haben oder nicht, sondern auch, wie Sie dorthin gekommen sind. Andernfalls könnten Sie denken, Sie hätten einen Zyklus gefunden, aber in Wirklichkeit haben Sie nur zwei getrennte Pfade A-> B, aber das bedeutet nicht, dass es einen Pfad B-> A gibt. Zum Beispiel,

Wenn Sie BFS ab 0, es wird erkannt, wenn ein Zyklus vorhanden ist, aber tatsächlich gibt es keinen Zyklus.

Mit einer Tiefensuche können Sie Knoten beim Abstieg als besucht markieren und beim Zurückverfolgen entfernen. In den Kommentaren finden Sie Informationen zur Leistungsverbesserung dieses Algorithmus.

Für den bester Algorithmus zur Erkennung von Zyklen in einem gerichteten Graphen können Sie Tarjans Algorithmus betrachten.

62
Mark Byers
  1. DFS ist einfacher zu implementieren
  2. Sobald DFS einen Zyklus gefunden hat, enthält der Stapel die Knoten, die den Zyklus bilden. Dasselbe gilt nicht für BFS. Sie müssen also zusätzliche Arbeit leisten, wenn Sie auch den gefundenen Zyklus drucken möchten. Dies macht DFS wesentlich komfortabler.
23
IVlad

Ein BFS kann sinnvoll sein, wenn der Graph ungerichtet ist (ich möchte einen effizienten Algorithmus mit BFS zeigen, der die Zyklen in einem gerichteten Graphen meldet!), Wobei jede "Cross Edge" einen Zyklus definiert. Wenn die Kreuzkante {v1, v2} Ist und die Wurzel (im BFS-Baum), die diese Knoten enthält, r ist, lautet der Zyklus r ~ v1 - v2 ~ r (~ ist ein Pfad (- eine einzelne Kante), der fast so einfach wie in DFS gemeldet werden kann.

Der einzige Grund, ein BFS zu verwenden, ist, wenn Sie wissen, dass Ihr (ungerichtetes) Diagramm lange Pfade und kleine Pfadabdeckungen (mit anderen Worten, tief und eng) aufweist. In diesem Fall würde BFS proportional weniger Speicher für seine Warteschlange benötigen als der DFS-Stapel (beide natürlich immer noch linear).

In allen anderen Fällen ist DFS eindeutig der Gewinner. Es funktioniert sowohl auf gerichteten als auch auf ungerichteten Graphen und es ist trivial, die Zyklen zu melden - beschränken Sie einfach eine beliebige Hinterkante auf den Pfad vom Vorfahren zum Nachkommen und Sie erhalten den Zyklus. Alles in allem viel besser und praktischer als BFS für dieses Problem.

10

BFS funktioniert nicht für einen gerichteten Graphen beim Finden von Zyklen. Betrachten Sie A-> B und A-> C-> B als Pfade von A nach B in einem Diagramm. BFS wird sagen, dass nach dem Gehen entlang eines der Wege, die B besucht wird. Wenn Sie den nächsten Weg fortsetzen, wird angezeigt, dass der markierte Knoten B erneut gefunden wurde. Daher ist ein Zyklus vorhanden. Natürlich gibt es hier keinen Zyklus.

2
Aditya Raman

Wenn Sie einen Zyklus an einer zufälligen Stelle in einem Baum platzieren, trifft die DFS den Zyklus in der Regel, wenn er etwa die Hälfte des Baums bedeckt und die Hälfte der Zeit, in der der Zyklus bereits durchlaufen wurde, nicht ( und wird es im Durchschnitt in der Hälfte des Restes des Baumes finden), so dass es im Durchschnitt etwa 0,5 * 0,5 + 0,5 * 0,75 = 0,625 des Baumes auswertet.

Wenn Sie einen Zyklus an einer zufälligen Stelle in einem Baum platzieren, trifft BFS den Zyklus in der Regel nur, wenn die Ebene des Baums in dieser Tiefe ausgewertet wird. Daher müssen Sie in der Regel die Blätter eines Balance-Binärbaums auswerten, was in der Regel dazu führt, dass mehr vom Baum ausgewertet werden. Insbesondere erscheinen 3/4 der Zeit mindestens eines der beiden Links in den Blättern des Baumes, und in diesen Fällen müssen Sie im Durchschnitt 3/4 des Baumes auswerten (wenn es einen Link gibt) oder 7/8 des Baumes (falls es zwei gibt), so dass Sie bereits der Erwartung gewachsen sind, 1/2 * 3/4 ​​+ 1/4 * 7/8 = (7 + 12)/32 = 21/32 = zu suchen 0,656 ... des Baums, ohne dass die Kosten für die Suche nach einem Baum mit einem von den Blattknoten entfernten Zyklus addiert werden.

Darüber hinaus ist DFS einfacher zu implementieren als BFS. Verwenden Sie diese Option, es sei denn, Sie wissen etwas über Ihre Zyklen (z. B. Zyklen befinden sich wahrscheinlich in der Nähe der Wurzel, von der aus Sie suchen, und an dieser Stelle bietet Ihnen BFS einen Vorteil).

2
Rex Kerr

Um zu beweisen, dass ein Graph zyklisch ist, müssen Sie nur einen Zyklus nachweisen (Edge zeigt entweder direkt oder indirekt auf sich selbst).

In der DFS nehmen wir jeweils einen Eckpunkt und prüfen, ob es einen Zyklus gibt. Sobald ein Zyklus gefunden wurde, können wir die Überprüfung anderer Scheitelpunkte weglassen.

In BFS müssen wir viele Scheitelpunktkanten gleichzeitig und meistens am Ende verfolgen, wenn Sie herausfinden, ob es einen Zyklus gibt. Da die Größe des Diagramms zunimmt, benötigt BFS im Vergleich zu DFS mehr Speicherplatz, Rechenaufwand und Zeit.

1
Spiker

Es hängt davon ab, ob es sich um rekursive oder iterative Implementierungen handelt.

Recursive-DFS besucht jeden Knoten zweimal. Iterative-BFS besucht jeden Knoten einmal.

Wenn Sie einen Zyklus erkennen möchten, müssen Sie die Knoten untersuchen, bevor und nachdem Sie ihre Nachbarschaften hinzugefügt haben - sowohl wenn Sie an einem Knoten "beginnen" als auch wenn Sie mit einem Knoten "enden".

Dies erfordert mehr Arbeit in Iterative-BFS, sodass sich die meisten Benutzer für Recursive-DFS entscheiden.

Beachten Sie, dass eine einfache Implementierung von Iterative-DFS mit beispielsweise std :: stack dasselbe Problem hat wie Iterative-BFS. In diesem Fall müssen Sie Dummy-Elemente in den Stapel einfügen, um zu verfolgen, wann Sie die Arbeit an einem Knoten "beendet" haben.

In dieser Antwort finden Sie weitere Informationen dazu, wie Iterative-DFS zusätzliche Arbeit erfordert, um festzustellen, wann Sie mit einem Knoten "fertig" sind (beantwortet im Kontext von TopoSort):

Topologische Sortierung mit DFS ohne Rekursion

Hoffentlich erklärt dies, warum Leute Recursive-DFS für Probleme bevorzugen, bei denen Sie feststellen müssen, wann Sie die Verarbeitung eines Knotens "beenden".

0
user755921