Si vous ne pouvez pas ajouter une propriété "visited" aux nœuds, utilisez un ensemble (ou une map) et ajoutez simplement tous les nœuds visités à l'ensemble sauf s'ils sont déjà dans l'ensemble. Utilisez une clé unique ou l'adresse des objets comme "clé".
Cela vous donne également des informations sur le nœud "racine" de la dépendance cyclique ce qui sera utile lorsque l'utilisateur devra résoudre le problème.
Une autre solution est d'essayer de trouver la prochaine dépendance à exécuter. Pour cela, vous devez avoir une pile où vous pouvez vous souvenir de où vous êtes maintenant et de ce que vous devez faire ensuite. Vérifiez si une dépendance est déjà sur cette pile avant de l'exécuter. Si c'est le cas, vous avez trouvé un cycle.
Alors que cela peut sembler avoir une complexité de O(N*M), vous devez vous rappeler que la pile a une profondeur très limitée (donc N est petit) et que M devient plus petit à chaque dépendance que vous pouvez cocher comme "exécutée" en plus vous pouvez arrêter la recherche lorsque vous trouvez une feuille (donc vous n'avez jamais à vérifier chaque nœud -> M sera également petit).
Dans MetaMake, j'ai créé le graphe comme une liste de listes puis j'ai supprimé chaque nœud au fur et à mesure que je les exécutais ce qui a naturellement réduit le volume de recherche. Je n'ai jamais eu besoin d'exécuter une vérification indépendante, tout s'est passé automatiquement pendant l'exécution normale.
Si vous avez besoin d'un mode "test uniquement", ajoutez simplement un indicateur "dry-run" qui désactive l'exécution des tâches réelles.
16 votes
Vous dites que vous voulez détecter tous les cycles, mais votre cas d'utilisation suggère qu'il serait suffisant de détecter s'il y a des cycles.
35 votes
Il serait préférable de détecter tous les cycles afin de les corriger en une seule fois, plutôt que de vérifier, corriger, vérifier, corriger, etc.
2 votes
Vous devriez lire l'article "Finding all the elementary circuits of a directed graph" de Donald B. Johnson. Il trouvera uniquement les circuits élémentaires, mais cela devrait être suffisant pour votre cas. Et voici mon implémentation en Java de cet algorithme prête à être utilisée : github.com/1123/johnson
0 votes
Exécutez DFS avec une modification supplémentaire pour l'algorithme: marquez chaque nœud visité. Si vous visitez un nœud qui est déjà visité, alors vous avez un cycle. Lorsque vous revenez en arrière depuis un chemin, démarquez les nœuds qui ont été visités.
4 votes
@HeshamYassin, si vous visitez un nœud que vous avez déjà visité, cela ne signifie pas nécessairement qu'il y a une boucle. Veuillez lire mon commentaire cs.stackexchange.com/questions/9676/….
0 votes
Votre première phrase contredit votre dernière phrase; veuillez corriger. Si vous voulez vraiment détecter tous les cycles (première phrase), la taille et le temps d'exécution de votre sortie dans le pire des cas seront exponentiels par rapport à la taille de votre entrée. Si vous voulez vraiment juste détecter le cas d'erreur de n'importe quel cycle (dernière phrase), vous pouvez le faire en un temps linéaire par rapport à la taille de l'entrée. Je recommande cette dernière option.
0 votes
@Pneauters non, il ne serait pas nécessairement mieux de détecter tous les cycles. Considérez le cas où il y en a un nombre exponentiel.
0 votes
Vous pouvez utiliser mon implémentation simple et efficace : stackoverflow.com/a/60196714/1763149