Finding all disconnected subgraphs in a graph

Viewed 37226

I have a graph which contains an unknown number of disconnected subgraphs. What's a good algorithm (or Java library) to find them all?

8 Answers

I probably should have found a standard algorithm (Wikipedia has some suggestions), but I came up with this on my own and it worked well for my purposes. My C# implementation takes a couple seconds to process a graph with 40,000 nodes and 44,000 edges to find 160 subgraphs and 20,000 unconnected nodes. I used a HashSet to store each subgraph group, so testing group membership is approximately O(1), and the overall algorithm becomes O(E*C) where E is the number of edges and C is the number of connected components in the graph. Wikipedia mentions an O(N) algorithm, linear in the number of nodes, so I'm sure mine is not maximally efficient, but it was plenty fast for my application. (Edit: I'm also glossing over the cost of merging groups, so don't put too much weight on my complexity analysis.)

Logic:

For each edge A->B
  If A is in a group and B is not, add B to group A
  If A is not in a group and B is, add A to group B
  If A and B are in different groups, merge the groups
  If neither A or B is in a group, create new group containing A and B

Pseudocode:

graph = {nodes, edges}
groups = {}
foreach edge A->B in graph.edges:
    groupA = findgroup(A)
    groupB = findgroup(B)
    if (groupA && !groupB)
        groupA.add(B)
    elif (!groupA && groupB)
        groupB.add(A)
    elif (groupA && groupB)
        if (groupA != groupB)
            groupA.union(groupB)
            groups.delete(groupB)
    else
        groups.add({A,B})
findgroup(node):
    for group in groups:
        if group.contains(node):
            return group
    return null

Note that this won't capture any nodes that aren't involved in edges. For my particular purposes this was fine. If you want to get all the single-node groups you can do a final pass:

foreach node in graph.nodes:
    group = findgroup(node)
    if !group:
        groups.add({node})

I ran into a similar problem where I wanted all the weakly connected subgraphs of a directed graph. I blogged about it here. I used the JUNG API and compare two approaches. My first approach could be used as a template to solve your problem.

Related