I have seen quite a lot of algorithms to do cycle detection, such as Tarjan's strongly connected components algorithm answered in Best algorithm for detecting cycles in a directed graph.
I never thought detecting a cycle would be that complicated and I always believed a simple Set
can help solve the problem.
So in addition to the usual marker
array for recording visited vertices, we can use an additional Set
to record all vertices along a path from the source.
The key thing is to remember to remove a vertex from the set after all its next neighbours are done.
A trivial code is like this:
public boolean hasCycle(List<Integer>[] vs) {
boolean[] marker = new boolean[v.length];
Set<Integer> tracker = new HashSet<Integer>();
for(int v = 0;v < vs.length;v++)
if (explore(v, vs, marker, tracker)) return true;
return false;
}
private boolean explore(int v, List<Integer>[] vs, boolean[] marker, Set<Integer> tracker) {
if (tracker.contains(v)) return true;
else if (!marker[v]) {
marker[v] = true;
tracker.add(v); // add current vertex to tracker
for (int u:vs[v]) if (explore(v, vs, marker, tracker)) return true;
tracker.remove(v); // remove the vertex from tracker, as it is fully done.
}
else return false;
}
Is there any problem about this algorithm?
With help from sasha's answer, actually even the set is not necessary and just an array is enough.
public boolean hasCycle(List<Integer>[] vs) {
boolean[] marker = new boolean[v.length];
boolean[] onPath = new boolean[v.length];
for(int v = 0;v < vs.length;v++)
if (explore(v, vs, marker, onPath)) return true;
return false;
}
private boolean explore(int v, List<Integer>[] vs, boolean[] marker, boolean[] onPath) {
if (onPath[v]) return true;
else if (!marker[v]) {
marker[v] = true;
onPath[v] = true; // add current vertex to the path
for (int u:vs[v]) if (explore(v, vs, marker, onPath)) return true;
onPath[v] = false; // remove the vertex from the path, as it is fully done.
}
else return false;
}