org.jgrapht.alg.ConnectivityInspector Maven / Gradle / Ivy
/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2008, by Barak Naveh and Contributors.
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
/* --------------------------
* ConnectivityInspector.java
* --------------------------
* (C) Copyright 2003-2008, by Barak Naveh and Contributors.
*
* Original Author: Barak Naveh
* Contributor(s): John V. Sichi
* Christian Hammer
*
* $Id$
*
* Changes
* -------
* 06-Aug-2003 : Initial revision (BN);
* 10-Aug-2003 : Adaptation to new event model (BN);
* 07-Jun-2005 : Made generic (CH);
*
*/
package org.jgrapht.alg;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.event.*;
import org.jgrapht.graph.*;
import org.jgrapht.traverse.*;
/**
* Allows obtaining various connectivity aspects of a graph. The inspected
* graph is specified at construction time and cannot be modified.
* Currently, the inspector supports connected components for an undirected
* graph and weakly connected components for a directed graph. To find strongly
* connected components, use {@link StrongConnectivityInspector} instead.
*
* The inspector methods work in a lazy fashion: no computation is performed
* unless immediately necessary. Computation are done once and results and
* cached within this class for future need.
*
* The inspector is also a {@link org.jgrapht.event.GraphListener}. If added
* as a listener to the inspected graph, the inspector will amend internal
* cached results instead of recomputing them. It is efficient when a few
* modifications are applied to a large graph. If many modifications are
* expected it will not be efficient due to added overhead on graph update
* operations. If inspector is added as listener to a graph other than the one
* it inspects, results are undefined.
*
* @author Barak Naveh
* @author John V. Sichi
* @since Aug 6, 2003
*/
public class ConnectivityInspector
implements GraphListener
{
List> connectedSets;
Map> vertexToConnectedSet;
private Graph graph;
/**
* Creates a connectivity inspector for the specified undirected graph.
*
* @param g the graph for which a connectivity inspector to be created.
*/
public ConnectivityInspector(UndirectedGraph g)
{
init();
this.graph = g;
}
/**
* Creates a connectivity inspector for the specified directed graph.
*
* @param g the graph for which a connectivity inspector to be created.
*/
public ConnectivityInspector(DirectedGraph g)
{
init();
this.graph = new AsUndirectedGraph(g);
}
/**
* Test if the inspected graph is connected. An empty graph is not
* considered connected.
*
* @return true
if and only if inspected graph is connected.
*/
public boolean isGraphConnected()
{
return lazyFindConnectedSets().size() == 1;
}
/**
* Returns a set of all vertices that are in the maximally connected
* component together with the specified vertex. For more on maximally
* connected component, see
* http://www.nist.gov/dads/HTML/maximallyConnectedComponent.html.
*
* @param vertex the vertex for which the connected set to be returned.
*
* @return a set of all vertices that are in the maximally connected
* component together with the specified vertex.
*/
public Set connectedSetOf(V vertex)
{
Set connectedSet = vertexToConnectedSet.get(vertex);
if (connectedSet == null) {
connectedSet = new HashSet();
BreadthFirstIterator i =
new BreadthFirstIterator(graph, vertex);
while (i.hasNext()) {
connectedSet.add(i.next());
}
vertexToConnectedSet.put(vertex, connectedSet);
}
return connectedSet;
}
/**
* Returns a list of Set
s, where each set contains all
* vertices that are in the same maximally connected component. All graph
* vertices occur in exactly one set. For more on maximally connected
* component, see
* http://www.nist.gov/dads/HTML/maximallyConnectedComponent.html.
*
* @return Returns a list of Set
s, where each set contains all
* vertices that are in the same maximally connected component.
*/
public List> connectedSets()
{
return lazyFindConnectedSets();
}
/**
* @see GraphListener#edgeAdded(GraphEdgeChangeEvent)
*/
@Override public void edgeAdded(GraphEdgeChangeEvent e)
{
init(); // for now invalidate cached results, in the future need to
// amend them.
}
/**
* @see GraphListener#edgeRemoved(GraphEdgeChangeEvent)
*/
@Override public void edgeRemoved(GraphEdgeChangeEvent e)
{
init(); // for now invalidate cached results, in the future need to
// amend them.
}
/**
* Tests if there is a path from the specified source vertex to the
* specified target vertices. For a directed graph, direction is ignored for
* this interpretation of path.
*
* Note: Future versions of this method might not ignore edge directions
* for directed graphs.
*
* @param sourceVertex one end of the path.
* @param targetVertex another end of the path.
*
* @return true
if and only if there is a path from the source
* vertex to the target vertex.
*/
public boolean pathExists(V sourceVertex, V targetVertex)
{
/*
* TODO: Ignoring edge direction for directed graph may be
* confusing. For directed graphs, consider Dijkstra's algorithm.
*/
Set sourceSet = connectedSetOf(sourceVertex);
return sourceSet.contains(targetVertex);
}
/**
* @see VertexSetListener#vertexAdded(GraphVertexChangeEvent)
*/
@Override public void vertexAdded(GraphVertexChangeEvent e)
{
init(); // for now invalidate cached results, in the future need to
// amend them.
}
/**
* @see VertexSetListener#vertexRemoved(GraphVertexChangeEvent)
*/
@Override public void vertexRemoved(GraphVertexChangeEvent e)
{
init(); // for now invalidate cached results, in the future need to
// amend them.
}
private void init()
{
connectedSets = null;
vertexToConnectedSet = new HashMap>();
}
private List> lazyFindConnectedSets()
{
if (connectedSets == null) {
connectedSets = new ArrayList>();
Set vertexSet = graph.vertexSet();
if (vertexSet.size() > 0) {
BreadthFirstIterator i =
new BreadthFirstIterator(graph, null);
i.addTraversalListener(new MyTraversalListener());
while (i.hasNext()) {
i.next();
}
}
}
return connectedSets;
}
/**
* A traversal listener that groups all vertices according to to their
* containing connected set.
*
* @author Barak Naveh
* @since Aug 6, 2003
*/
private class MyTraversalListener
extends TraversalListenerAdapter
{
private Set currentConnectedSet;
/**
* @see TraversalListenerAdapter#connectedComponentFinished(ConnectedComponentTraversalEvent)
*/
@Override public void connectedComponentFinished(
ConnectedComponentTraversalEvent e)
{
connectedSets.add(currentConnectedSet);
}
/**
* @see TraversalListenerAdapter#connectedComponentStarted(ConnectedComponentTraversalEvent)
*/
@Override public void connectedComponentStarted(
ConnectedComponentTraversalEvent e)
{
currentConnectedSet = new HashSet();
}
/**
* @see TraversalListenerAdapter#vertexTraversed(VertexTraversalEvent)
*/
@Override public void vertexTraversed(VertexTraversalEvent e)
{
V v = e.getVertex();
currentConnectedSet.add(v);
vertexToConnectedSet.put(v, currentConnectedSet);
}
}
}
// End ConnectivityInspector.java