463 Stimmen

Bester Algorithmus zur Erkennung von Zyklen in einem gerichteten Graphen

Gibt es einen effizienten Algorithmus zur Erkennung von Zyklen innerhalb eines gerichteten Graphen?

Ich habe einen gerichteten Graphen, der einen Zeitplan von auszuführenden Aufträgen darstellt, wobei ein Auftrag ein Knoten und eine Abhängigkeit eine Kante ist. Ich muss den Fehlerfall eines Zyklus innerhalb dieses Graphen erkennen, der zu zyklischen Abhängigkeiten führt.

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

29voto

Ajay Garg Punkte 307

Beginnen Sie mit einem DFS: Ein Zyklus existiert nur dann, wenn a die Hinterkante wird beim DFS entdeckt . Dies wird als Ergebnis des Theorems des weißen Pfades bewiesen.

4 Stimmen

Ja, ich denke dasselbe, aber das ist nicht genug, ich poste meinen Weg cs.stackexchange.com/questions/7216/find-the-simple-cycles-in-a-directed-graph

0 Stimmen

Das stimmt. Ajay Garg erzählt nur, wie man "einen Zyklus" findet, was eine Teilantwort auf diese Frage ist. Ihr Link spricht davon, alle Zyklen gemäß der gestellten Frage zu finden, aber auch hier sieht es so aus, als ob er den gleichen Ansatz wie Ajay Garg verwendet, aber auch alle möglichen dfs-Bäume.

0 Stimmen

Bei gerichteten Graphen ist dies unvollständig. Siehe die richtige Antwort von Kurt Peek.

9voto

Aaron Digulla Punkte 308693

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.

8voto

Yuwen Punkte 953

Es gibt keinen Algorithmus, der alle Zyklen in einem gerichteten Graphen in polynomieller Zeit finden kann. Nehmen wir an, der gerichtete Graph hat n Knoten und jedes Knotenpaar hat Verbindungen zueinander, d.h. es handelt sich um einen vollständigen Graphen. Jede nicht leere Teilmenge dieser n Knoten ist also ein Zyklus, und es gibt 2^n-1 solcher Teilmengen. Es gibt also keinen Polynomialzeit-Algorithmus. Angenommen, man hat einen effizienten (nicht dummen) Algorithmus, der die Anzahl der gerichteten Zyklen in einem Graphen ermitteln kann, so kann man zunächst die stark zusammenhängenden Komponenten finden und dann den Algorithmus auf diese Komponenten anwenden. Denn Zyklen gibt es nur innerhalb der Komponenten und nicht zwischen ihnen.

1 Stimmen

Wahr, wenn die Anzahl der Knoten als Größe der Eingabe angenommen wird. Man könnte die Laufzeitkomplexität auch in Form der Anzahl der Kanten oder sogar der Zyklen oder einer Kombination dieser Maße beschreiben. Der Algorithmus "Finding all the elementary circuits of a directed graph" von Donald B. Johnson hat eine polynomielle Laufzeit von O((n + e)(c + 1)), wobei n die Anzahl der Knoten, e die Anzahl der Kanten und c die Anzahl der Elementarkreise des Graphen ist. Und hier ist meine Java-Implementierung dieses Algorithmus: github.com/1123/johnson .

1voto

Steve Punkte 6242

Ich führe eine topologische Sortierung durch und zähle die Anzahl der besuchten Scheitelpunkte. Wenn diese Zahl kleiner ist als die Gesamtzahl der Knoten in der DAG, haben Sie einen Zyklus.

5 Stimmen

Das macht keinen Sinn. Wenn der Graph Zyklen hat, gibt es keine topologische Sortierung, was bedeutet, dass jeder korrekte Algorithmus für topologische Sortierung abbricht.

5 Stimmen

Aus wikipedia: Viele topologische Sortieralgorithmen erkennen auch Zyklen, da diese ein Hindernis für die Existenz einer topologischen Ordnung darstellen.

1 Stimmen

@OlegMikheev Ja, aber Steve sagt: "Wenn diese Zahl kleiner ist als die Gesamtzahl der Scheitelpunkte in der DAG, haben Sie einen Zyklus", was keinen Sinn ergibt.

0voto

Bhagwati Malav Punkte 2899

Wie Sie sagten, haben Sie eine Reihe von Aufträgen, die in einer bestimmten Reihenfolge ausgeführt werden müssen. Topological sort für die Planung von Aufträgen (oder für Abhängigkeitsprobleme, wenn es sich um eine direct acyclic graph ). ausführen. dfs und pflegen Sie eine Liste, und beginnen Sie mit dem Hinzufügen von Knoten am Anfang der Liste, und wenn Sie auf einen Knoten stoßen, der bereits besucht wird. Dann haben Sie einen Zyklus im gegebenen Graphen gefunden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X