A simple algorithm we use for finding cycles in graphs:
Create a depth-first spanning tree
where each node has a parent.
In traversing the tree create a record of used nodes.
When an edge points to a previously used node, store it as a
cyclic edge.
When the spanning tree is complete, the count of the cyclic
edges gives the count of cycles.
For each cyclic edge recurse through the ancestors of the two nodes
until a common ancestor is found. That
will give exactly the cycles.
It may be useful to have an index (hashtable) of all the ancestors of a cyclic edge node so that is quick to find the common ancestor.
I doubt this is the best algorithm but it is fairly quick.
EDIT in repsonse to comment
Each node in the spanning tree has a parent. When a node in a cyclic edge is reached it calculates its list of ancestors (List<Node>
This list could be indexed for speed (i.e. contains() is < O(n))
. When a cyclic edge with two nodes (n1, n2
) is found then iterate through the ancestors of n1, n1.ancestorList
(rapidly since the list has already been created) and test whether the ancestor is in n2.ancestorList
. If it (commonAncestor
) is, then exactly those ancestors traversed correspond to cycles. Then iterate through n2 until you reach commonAncestor
(rapid). The time should depend on the number of cyclic edges, combined with the lookup in lists (probably O(logN)
but cheap). There is no need to re-explore the graph and there is no backtracking.