package org.insa.algo.weakconnectivity; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.HashSet; import org.insa.algo.AbstractAlgorithm; import org.insa.algo.AbstractSolution.Status; import org.insa.graph.Arc; import org.insa.graph.Graph; import org.insa.graph.Node; public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm{ /** * * @param instance * @param logOutput */ public WeaklyConnectedComponentsAlgorithm(WeaklyConnectedComponentsData instance) { super(instance); } @Override public WeaklyConnectedComponentsSolution run() { return (WeaklyConnectedComponentsSolution)super.run(); } @Override public WeaklyConnectedComponentsData getInstance() { return (WeaklyConnectedComponentsData)super.getInstance(); } /** * Notify all observers that the algorithm is entering a new component. * * @param curNode Starting node for the component. */ protected void notifyStartComponent(Node curNode) { for (WeaklyConnectedComponentObserver obs: getObservers()) { obs.notifyStartComponent(curNode); } } /** * Notify all observers that a new node has been found for the current component. * * @param node New node found for the current component. */ protected void notifyNewNodeInComponent(Node node) { for (WeaklyConnectedComponentObserver obs: getObservers()) { obs.notifyNewNodeInComponent(node); } } /** * Notify all observers that the algorithm has computed a new component. * * @param nodes List of nodes in the component. */ protected void notifyEndComponent(ArrayList nodes) { for (WeaklyConnectedComponentObserver obs: getObservers()) { obs.notifyEndComponent(nodes); } } /** * @return An adjacency list for the undirected graph equivalent to the stored graph. */ protected ArrayList> createUndirectedGraph() { int nNodes = getInstance().getGraph().getNodes().size(); ArrayList> res = new ArrayList>(nNodes); for (int i = 0; i < nNodes; ++i) { res.add(new HashSet()); } for (Node node: getInstance().getGraph().getNodes()) { for (Arc arc: node.getSuccessors()) { res.get(node.getId()).add(arc.getDestination().getId()); if (arc.getInfo().isOneWay()) { res.get(arc.getDestination().getId()).add(node.getId()); } } } return res; } /** * Apply a breadth first search algorithm on the given undirected graph (adjacency list), * starting at node cur, and marking nodes in marked. * * @param marked * @param cur * * @return */ protected ArrayList bfs(ArrayList> ugraph, boolean[] marked, int cur) { ArrayList nodes = getInstance().getGraph().getNodes(); ArrayList component = new ArrayList(); // Using a queue because we are doing a BFS Queue queue = new LinkedList(); // Notify observers about the current component. notifyStartComponent(nodes.get(cur)); // Add original node and loop until the queue is empty. queue.add(cur); marked[cur] = true; while (!queue.isEmpty()) { Node node = nodes.get(queue.remove()); component.add(node); // Notify observers notifyNewNodeInComponent(node); for (Integer destId: ugraph.get(node.getId())) { Node dest = nodes.get(destId); if (!marked[dest.getId()]) { queue.add(destId); marked[destId] = true; } } } notifyEndComponent(component); return component; } @Override protected WeaklyConnectedComponentsSolution doRun() { Graph graph = getInstance().getGraph(); ArrayList> ugraph = createUndirectedGraph(); boolean[] marked = new boolean[graph.getNodes().size()]; Arrays.fill(marked, false); ArrayList> components = new ArrayList>(); // perform algorithm int cur = 0; while (cur < marked.length) { // Apply BFS components.add(this.bfs(ugraph, marked, cur)); // Find next non-marked for (; cur < marked.length && marked[cur]; ++cur); } return new WeaklyConnectedComponentsSolution(getInstance(), Status.OPTIMAL, components); } }