3

I'm seeking to improve my solution to find all weakly connected components in a directed graph using Quick-Find algorithm.

Problem Statement

Given a list of DirectedGraphNode, find all islands (i.e weakly connected components).

public class DirectedGraphNode {
    String val;
    List<DirectedGraphNode> neighbors;
}

Thus, given following directed graph:

A —> B —> <— C 
     ^
     |
     E <— F —> D —> G

X -> <- Y

node : neighbors
  A  :  [B]
  B  :  [C, E]
  C  :  [B]
  D  :  [G]
  E  :  []
  F  :  [E, D]
  G  :  []
  X  :  [Y]
  Y  :  [X]

The output should be as follows (order doesn't matter):

[
   [A, B, C, E, D, F, G],
   [X, Y]
]

I solved this using Quick-Find algorithm. Code below:

public static List<List<Node>> connectedComponents(List<Node> nodes) {
    if (nodes == null || nodes.size() == 0) {
        throw new IllegalArgumentException("List node is empty");
    }

    // Maintain array with name for each element
    String[] labels = new String[nodes.size()];
    // Initially, set the labels of each element to itself
    // Use HashMap to memorize the index
    Map<String, Integer> map = new HashMap<>();
    for (int i = 0; i < labels.length; i++) {
        labels[i] = nodes.get(i).val;
        map.put(nodes.get(i).val, i);
    }

    for (Node node : nodes) {
        if (node.neighbors == null || node.neighbors.isEmpty()) {
            continue;
        }

        int changerIdx = map.get(node.val);
        for (Node nbr : node.neighbors) {
            int changeeIdx = map.get(nbr.val);
            String symbol = labels[changeeIdx];
            for (int i = 0; i < labels.length; i++) {
                if (labels[i] == symbol) {
                    labels[i] = labels[changerIdx];
                }
            }
        }
    }
    return createIslandList(labels, nodes);
}

private static List<List<Node>> createIslandList(String[] labels, List<Node> nodes) {
    List<List<Node>> res = new ArrayList<List<Node>>();
    if (labels == null || labels.length == 0) {
        return res;
    }

    Map<String, List<Node>> map = new HashMap<String, List<Node>>();
    for (int i = 0; i < labels.length; i++) {
        if (!map.containsKey(labels[i])) {
            List<Node> island = new ArrayList<>();
            island.add(nodes.get(i));
            map.put(labels[i], island);
        } else {
            map.get(labels[i]).add(nodes.get(i));
        }
    }

    for (String key : map.keySet()) {
        res.add(map.get(key));
    }

    return res;
}

However, this algorithm in the worst case runs in O(N^3) since each time it needs to do linear search for union. I'm very curious if there is any way to improve this.

Thank you for your suggestion!

gyoho
  • 799
  • 2
  • 9
  • 25
  • I am not sure about its performance http://jgrapht.org/javadoc/org/jgrapht/alg/ConnectivityInspector.html from JGraphT so just a tip: "Currently, the inspector supports connected components for an undirected graph and weakly connected components for a directed graph" – serg.nechaev Aug 17 '16 at 02:50

1 Answers1

1

This is an edited answer. Sorry that I was confused between weakly connected components and strongly connected components.

It's actually very straightforward to determine weakly connected components. Just convert all edges to be undirected and perform BFS or DFS.

The run time will be O(|V| + |E|) where V is the set of vertices and E is the set of edges.

wookie919
  • 3,054
  • 24
  • 32
  • Java implementation: http://jgrapht.org/javadoc/org/jgrapht/alg/package-summary.html – serg.nechaev Aug 17 '16 at 02:52
  • @wookie919 I'm just wondering the runtime complexity of converting all the edges to be undirected. What is a good way to do this conversion? – gyoho Aug 17 '16 at 04:07
  • @gyoho If `B` is a neighbor of `A`, add `A` as the neighbor of `B`. This will take `O(|E|)` time. – wookie919 Aug 17 '16 at 04:15
  • @wookie919 For further optimization, I would change the data structure of `neighbors` from `List` to `Set` to achieve `O(1)` lookup for searching the `neighbors` in order to avoid adding duplicates. – gyoho Aug 17 '16 at 05:05