Vorwiegend wird DFS verwendet, um einen Zyklus in Diagrammen und nicht in BFS zu finden. Irgendwelche Gründe? Beide können feststellen, ob beim Durchlaufen des Baums / Diagramms bereits ein Knoten besucht wurde.
algorithm
tree
graph-theory
depth-first-search
breadth-first-search
schlechte Gesellschaft
quelle
quelle
Antworten:
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 hängt jedoch davon ab, dass der längste Pfad den Stapel nicht überläuft.
Auch wenn Ihr Diagramm ist gerichtet dann müssen Sie nicht nur daran erinnern , wenn Sie einen Knoten oder nicht besucht haben, sondern auch , wie du da. Andernfalls könnten Sie denken, Sie hätten einen Zyklus gefunden, aber in Wirklichkeit haben Sie nur zwei separate Pfade A-> B, aber das bedeutet nicht, dass es einen Pfad B-> A gibt. Beispielsweise,
Wenn Sie BFS ab ausführen
0
, wird erkannt, dass ein Zyklus vorhanden ist, aber tatsächlich kein Zyklus vorhanden ist.Bei einer Tiefensuche können Sie Knoten beim Besuch als besucht markieren und beim Zurückverfolgen die Markierung aufheben. In den Kommentaren finden Sie eine Leistungsverbesserung für diesen Algorithmus.
Den besten Algorithmus zum Erkennen von Zyklen in einem gerichteten Graphen finden Sie im Tarjan-Algorithmus .
quelle
quelle
Ein BFS könnte sinnvoll sein, wenn das Diagramm ungerichtet ist (sei mein Gast, wenn es darum geht, einen effizienten Algorithmus mit BFS zu zeigen, der die Zyklen in einem gerichteten Diagramm meldet!), Wobei jede "Kreuzkante" einen Zyklus definiert. Wenn die Querkante
{v1, v2}
und die Wurzel (im BFS-Baum), die diese Knoten enthält, istr
, ist der Zyklusr ~ v1 - v2 ~ r
(~
ist ein Pfad,-
eine einzelne Kante), der fast so einfach wie in DFS gemeldet werden kann.Der einzige Grund für die Verwendung eines BFS wäre, wenn Sie wissen, dass Ihr (ungerichteter) Graph lange Pfade und eine kleine Pfadabdeckung aufweist (mit anderen Worten, tief und schmal). In diesem Fall würde BFS proportional weniger Speicher für seine Warteschlange benötigen als der Stapel von DFS (beide natürlich immer noch linear).
In allen anderen Fällen ist die DFS eindeutig der Gewinner. Es funktioniert sowohl mit gerichteten als auch mit ungerichteten Graphen, und es ist trivial, die Zyklen zu melden. Konzentrieren 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.
quelle
BFS funktioniert beim Finden von Zyklen nicht für einen gerichteten Graphen. Betrachten Sie A-> B und A-> C-> B als Pfade von A nach B in einem Diagramm. BFS wird sagen, dass nach dem Gehen eines der Pfade, die B besucht wird. Wenn Sie den nächsten Pfad weiterfahren, wird angezeigt, dass der markierte Knoten B erneut gefunden wurde, sodass ein Zyklus vorhanden ist. Hier gibt es eindeutig keinen Zyklus.
quelle
Ich weiß nicht, warum so eine alte Frage in meinem Feed aufgetaucht ist, aber alle vorherigen Antworten sind schlecht, also ...
DFS wird verwendet, um Zyklen in gerichteten Graphen zu finden, da es funktioniert .
In einer DFS wird jeder Scheitelpunkt "besucht", wobei der Besuch eines Scheitelpunkts bedeutet:
Der von diesem Scheitelpunkt aus erreichbare Untergraph wird besucht. Dies umfasst das Verfolgen aller nicht verfolgten Kanten, die von diesem Scheitelpunkt aus erreichbar sind, und das Aufrufen aller erreichbaren nicht besuchten Scheitelpunkte.
Der Scheitelpunkt ist fertig.
Das entscheidende Merkmal ist, dass alle von einem Scheitelpunkt aus erreichbaren Kanten verfolgt werden, bevor der Scheitelpunkt fertig ist. Dies ist eine Funktion von DFS, jedoch nicht von BFS. In der Tat ist dies die Definition von DFS.
Aufgrund dieser Funktion wissen wir, dass beim Starten des ersten Scheitelpunkts in einem Zyklus:
Wenn es also einen Zyklus gibt, finden wir garantiert eine Kante zu einem gestarteten, aber noch nicht abgeschlossenen Scheitelpunkt (2), und wenn wir eine solche Kante finden, ist uns garantiert, dass es einen Zyklus gibt (3).
Aus diesem Grund wird DFS verwendet, um Zyklen in gerichteten Graphen zu finden.
BFS bietet keine solchen Garantien, daher funktioniert es einfach nicht. (ungeachtet perfekt guter Algorithmen zur Zyklusfindung, die BFS oder ähnliches als Teilprozedur enthalten)
Ein ungerichteter Graph hat andererseits einen Zyklus, wenn zwischen einem Scheitelpunktpaar zwei Pfade liegen, dh wenn es sich nicht um einen Baum handelt. Dies ist während BFS oder DFS leicht zu erkennen. - Die Kanten, die auf neue Scheitelpunkte zurückgeführt werden, bilden einen Baum, und jede andere Kante zeigt einen Zyklus an.
quelle
Wenn Sie einen Zyklus an einer zufälligen Stelle in einem Baum platzieren, trifft DFS den Zyklus in der Regel, wenn er ungefähr die Hälfte des Baums bedeckt hat und die Hälfte der Zeit, in der er bereits den Zyklus durchlaufen hat, und die Hälfte der Zeit nicht ( und findet es im Durchschnitt in der Hälfte des restlichen Baumes), so dass es im Durchschnitt etwa 0,5 * 0,5 + 0,5 * 0,75 = 0,625 des Baumes bewertet.
Wenn Sie einen Zyklus an einer zufälligen Stelle in einem Baum platzieren, trifft BFS den Zyklus in der Regel nur dann, wenn die Ebene des Baums in dieser Tiefe ausgewertet wird. Daher müssen Sie normalerweise die Blätter eines Balance-Binärbaums bewerten, was im Allgemeinen dazu führt, dass mehr vom Baum bewertet werden. Insbesondere erscheint 3/4 der Zeit mindestens einer der beiden Links in den Blättern des Baums, und in diesen Fällen müssen Sie durchschnittlich 3/4 des Baums (wenn es einen Link gibt) oder 7 / bewerten. 8 des Baums (wenn es zwei gibt), sodass Sie bereits die Erwartung haben, 1/2 * 3/4 + 1/4 * 7/8 = (7 + 12) / 32 = 21/32 = zu suchen 0,656 ... des Baums, ohne die Kosten für die Suche nach einem Baum mit einem Zyklus zu addieren, der von den Blattknoten weg hinzugefügt wird.
Darüber hinaus ist DFS einfacher zu implementieren als BFS. Es ist also diejenige, die Sie verwenden sollten, es sei denn, Sie wissen etwas über Ihre Zyklen (z. B. befinden sich Zyklen wahrscheinlich in der Nähe der Wurzel, von der aus Sie suchen, und an diesem Punkt bietet Ihnen BFS einen Vorteil).
quelle
Um zu beweisen, dass ein Graph zyklisch ist, müssen Sie nur beweisen, dass er einen Zyklus hat (die Kante zeigt entweder direkt oder indirekt auf sich selbst).
In der DFS nehmen wir jeweils einen Scheitelpunkt und prüfen, ob er einen Zyklus hat. Sobald ein Zyklus gefunden wurde, können wir die Überprüfung anderer Scheitelpunkte unterlassen.
In BFS müssen wir viele Scheitelpunktkanten gleichzeitig verfolgen und am Ende finden Sie meistens heraus, ob es einen Zyklus gibt. Mit zunehmender Größe des Diagramms benötigt BFS im Vergleich zu DFS mehr Platz, Berechnung und Zeit.
quelle
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 sowohl vor als auch nach dem Hinzufügen ihrer Nachbarschaften untersuchen - sowohl beim "Starten" eines Knotens als auch beim "Beenden" eines Knotens.
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 das gleiche Problem wie Iterative-BFS hat. 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 bestimmen müssen, wann Sie die Verarbeitung eines Knotens "beenden".
quelle
Sie müssen verwenden,
BFS
wenn Sie den kürzesten Zyklus mit einem bestimmten Knoten in einem gerichteten Diagramm suchen möchten.Z.B:
Wenn der angegebene Knoten 2 ist, gibt es drei Zyklen, in denen er Teil von - ist.
[2,3,4]
,[2,3,4,5,6,7,8,9]
& ist[2,5,6,7,8,9]
. Am kürzesten ist[2,3,4]
Um dies mit BFS zu implementieren, müssen Sie den Verlauf der besuchten Knoten mithilfe geeigneter Datenstrukturen explizit verwalten.
Für alle anderen Zwecke (z. B. um einen zyklischen Pfad zu finden oder um zu überprüfen, ob ein Zyklus vorhanden ist oder nicht)
DFS
ist dies aus von anderen genannten Gründen die klare Wahl.quelle