Wenn Sie den Knoten keine Eigenschaft "besucht" hinzufügen können, verwenden Sie eine Menge (oder eine Karte) und fügen Sie einfach alle besuchten Knoten der Menge hinzu, sofern sie nicht bereits in der Menge enthalten sind. Verwenden Sie einen eindeutigen Schlüssel oder die Adresse der Objekte als "Schlüssel".
Dadurch erhalten Sie auch Informationen über den "Root"-Knoten der zyklischen Abhängigkeit, was sich als nützlich erweisen wird, wenn ein Benutzer das Problem beheben muss.
Eine andere Lösung besteht darin, zu versuchen, die nächste auszuführende Abhängigkeit zu finden. Dazu müssen Sie einen Stapel haben, auf dem Sie sich merken können, wo Sie sich gerade befinden und was Sie als nächstes tun müssen. Prüfen Sie, ob sich eine Abhängigkeit bereits auf diesem Stapel befindet, bevor Sie sie ausführen. Wenn ja, haben Sie einen Zyklus gefunden.
Auch wenn dies eine Komplexität von O(N*M) zu haben scheint, darf man nicht vergessen, dass der Stapel eine sehr begrenzte Tiefe hat (daher ist N klein) und dass M mit jeder Abhängigkeit, die man als "ausgeführt" abhaken kann, kleiner wird, und dass man die Suche beenden kann, wenn man ein Blatt gefunden hat (daher kann man niemals jeden Knoten überprüfen müssen -> M wird ebenfalls klein sein).
In MetaMake habe ich den Graphen als eine Liste von Listen erstellt und dann jeden Knoten bei der Ausführung gelöscht, was natürlich das Suchvolumen reduzierte. Ich musste eigentlich nie eine unabhängige Prüfung durchführen, das geschah alles automatisch während der normalen Ausführung.
Wenn Sie einen "Nur-Test"-Modus benötigen, fügen Sie einfach ein "Trockenlauf"-Flag hinzu, das die Ausführung der eigentlichen Aufträge deaktiviert.
21 Stimmen
Sie sagen, Sie wollen alle Zyklen erkennen, aber Ihr Anwendungsfall legt nahe, dass es ausreichen würde, zu erkennen, ob es irgendwelche Zyklen gibt.
38 Stimmen
Es wäre besser, alle Zyklen aufzuspüren, damit sie in einem Zug behoben werden können, als zu prüfen, zu beheben, zu prüfen, zu beheben usw.
2 Stimmen
Sie sollten die Arbeit "Finding all the elementary circuits of a directed graph" von Donald B. Johnson lesen. Es werden zwar nur elementare Schaltungen gefunden, aber das sollte für Ihren Fall ausreichen. Und hier ist meine Java-Implementierung dieses Algorithmus zur Verwendung bereit: github.com/1123/johnson
0 Stimmen
Führen Sie DFS mit einer zusätzlichen Änderung für den Algorithmus aus: Markieren Sie jeden Knoten, den Sie besucht haben. Wenn Sie einen Knoten besuchen, der bereits besucht ist, haben Sie einen Cicle. Wenn Sie sich von einem Pfad zurückziehen, entfernen Sie die Markierung der besuchten Knoten.
9 Stimmen
@HeshamYassin, wenn Sie einen Knoten besuchen, den Sie bereits besucht haben, bedeutet das nicht unbedingt, dass es eine Schleife gibt. Bitte lesen Sie meinen Kommentar cs.stackexchange.com/questions/9676/ .
0 Stimmen
Ihr erster Satz widerspricht Ihrem letzten Satz; bitte korrigieren Sie ihn. Wenn Sie wirklich erkennen wollen alle die Zyklen (erster Satz), die Größe der Ausgabe und die Laufzeit sind im schlimmsten Fall exponentiell zur Größe der Eingabe. Wenn Sie wirklich nur den Fehlerfall von cualquier Zyklus (letzter Satz) können Sie das in einer Zeit tun, die linear zur Größe der Eingabe ist. Ich würde Letzteres empfehlen.
0 Stimmen
@Pneauters Nein, es wäre nicht unbedingt besser, alle Zyklen zu erkennen. Betrachten Sie den Fall, dass es eine exponentielle Anzahl von Zyklen gibt.
0 Stimmen
Sie können meine einfache und effektive Umsetzung nutzen: stackoverflow.com/a/60196714/1763149