org.jgrapht.traverse.CrossComponentIterator Maven / Gradle / Ivy
Go to download
JGraphT is a free Java graph library
that provides mathematical graph-theory objects and algorithms
The newest version!
/* ==========================================
* 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-2007, by Barak Naveh and Contributors.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
/* ---------------------------
* CrossComponentIterator.java
* ---------------------------
* (C) Copyright 2003-2007, by Barak Naveh and Contributors.
*
* Original Author: Barak Naveh
* Contributor(s): John V. Sichi
* Christian Hammer
*
* $Id: CrossComponentIterator.java 568 2007-09-30 00:12:18Z perfecthash $
*
* Changes
* -------
* 31-Jul-2003 : Initial revision (BN);
* 11-Aug-2003 : Adaptation to new event model (BN);
* 31-Jan-2004 : Extracted cross-component traversal functionality (BN);
* 04-May-2004 : Made generic (CH)
* 07-May-2006 : Changed from List to Set (JVS);
*
*/
package org.jgrapht.traverse;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.event.*;
/**
* Provides a cross-connected-component traversal functionality for iterator
* subclasses.
*
* @param vertex type
* @param edge type
* @param type of data associated to seen vertices
*
* @author Barak Naveh
* @since Jan 31, 2004
*/
public abstract class CrossComponentIterator
extends AbstractGraphIterator
{
//~ Static fields/initializers ---------------------------------------------
private static final int CCS_BEFORE_COMPONENT = 1;
private static final int CCS_WITHIN_COMPONENT = 2;
private static final int CCS_AFTER_COMPONENT = 3;
//~ Enums ------------------------------------------------------------------
/**
* Standard vertex visit state enumeration.
*/
protected static enum VisitColor
{
/**
* Vertex has not been returned via iterator yet.
*/
WHITE,
/**
* Vertex has been returned via iterator, but we're
* not done with all of its out-edges yet.
*/
GRAY,
/**
* Vertex has been returned via iterator, and we're
* done with all of its out-edges.
*/
BLACK
}
//~ Instance fields --------------------------------------------------------
//
private final ConnectedComponentTraversalEvent ccFinishedEvent =
new ConnectedComponentTraversalEvent(
this,
ConnectedComponentTraversalEvent.CONNECTED_COMPONENT_FINISHED);
private final ConnectedComponentTraversalEvent ccStartedEvent =
new ConnectedComponentTraversalEvent(
this,
ConnectedComponentTraversalEvent.CONNECTED_COMPONENT_STARTED);
// TODO: support ConcurrentModificationException if graph modified
// during iteration.
private FlyweightEdgeEvent reusableEdgeEvent;
private FlyweightVertexEvent reusableVertexEvent;
private Iterator vertexIterator = null;
/**
* Stores the vertices that have been seen during iteration and (optionally)
* some additional traversal info regarding each vertex.
*/
private Map seen = new HashMap();
private V startVertex;
private Specifics specifics;
private final Graph graph;
/**
* The connected component state
*/
private int state = CCS_BEFORE_COMPONENT;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new iterator for the specified graph. Iteration will start at
* the specified start vertex. If the specified start vertex is
* null
, Iteration will start at an arbitrary graph vertex.
*
* @param g the graph to be iterated.
* @param startVertex the vertex iteration to be started.
*
* @throws IllegalArgumentException if g==null
or does not
* contain startVertex
*/
public CrossComponentIterator(Graph g, V startVertex)
{
super();
if (g == null) {
throw new IllegalArgumentException("graph must not be null");
}
graph = g;
specifics = createGraphSpecifics(g);
vertexIterator = g.vertexSet().iterator();
setCrossComponentTraversal(startVertex == null);
reusableEdgeEvent = new FlyweightEdgeEvent(this, null);
reusableVertexEvent = new FlyweightVertexEvent(this, null);
if (startVertex == null) {
// pick a start vertex if graph not empty
if (vertexIterator.hasNext()) {
this.startVertex = vertexIterator.next();
} else {
this.startVertex = null;
}
} else if (g.containsVertex(startVertex)) {
this.startVertex = startVertex;
} else {
throw new IllegalArgumentException(
"graph must contain the start vertex");
}
}
//~ Methods ----------------------------------------------------------------
/**
* @return the graph being traversed
*/
public Graph getGraph()
{
return graph;
}
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext()
{
if (startVertex != null) {
encounterStartVertex();
}
if (isConnectedComponentExhausted()) {
if (state == CCS_WITHIN_COMPONENT) {
state = CCS_AFTER_COMPONENT;
fireConnectedComponentFinished(ccFinishedEvent);
}
if (isCrossComponentTraversal()) {
while (vertexIterator.hasNext()) {
V v = vertexIterator.next();
if (!isSeenVertex(v)) {
encounterVertex(v, null);
state = CCS_BEFORE_COMPONENT;
return true;
}
}
return false;
} else {
return false;
}
} else {
return true;
}
}
/**
* @see java.util.Iterator#next()
*/
public V next()
{
if (startVertex != null) {
encounterStartVertex();
}
if (hasNext()) {
if (state == CCS_BEFORE_COMPONENT) {
state = CCS_WITHIN_COMPONENT;
fireConnectedComponentStarted(ccStartedEvent);
}
V nextVertex = provideNextVertex();
fireVertexTraversed(createVertexTraversalEvent(nextVertex));
addUnseenChildrenOf(nextVertex);
return nextVertex;
} else {
throw new NoSuchElementException();
}
}
/**
* Returns true if there are no more uniterated vertices in the
* currently iterated connected component; false otherwise.
*
* @return true if there are no more uniterated vertices in the
* currently iterated connected component; false otherwise.
*/
protected abstract boolean isConnectedComponentExhausted();
/**
* Update data structures the first time we see a vertex.
*
* @param vertex the vertex encountered
* @param edge the edge via which the vertex was encountered, or null if the
* vertex is a starting point
*/
protected abstract void encounterVertex(V vertex, E edge);
/**
* Returns the vertex to be returned in the following call to the iterator
* next
method.
*
* @return the next vertex to be returned by this iterator.
*/
protected abstract V provideNextVertex();
/**
* Access the data stored for a seen vertex.
*
* @param vertex a vertex which has already been seen.
*
* @return data associated with the seen vertex or null
if no
* data was associated with the vertex. A null
return can also
* indicate that the vertex was explicitly associated with
* null
.
*/
protected D getSeenData(V vertex)
{
return seen.get(vertex);
}
/**
* Determines whether a vertex has been seen yet by this traversal.
*
* @param vertex vertex in question
*
* @return true if vertex has already been seen
*/
protected boolean isSeenVertex(Object vertex)
{
return seen.containsKey(vertex);
}
/**
* Called whenever we re-encounter a vertex. The default implementation does
* nothing.
*
* @param vertex the vertex re-encountered
* @param edge the edge via which the vertex was re-encountered
*/
protected abstract void encounterVertexAgain(V vertex, E edge);
/**
* Stores iterator-dependent data for a vertex that has been seen.
*
* @param vertex a vertex which has been seen.
* @param data data to be associated with the seen vertex.
*
* @return previous value associated with specified vertex or
* null
if no data was associated with the vertex. A
* null
return can also indicate that the vertex was explicitly
* associated with null
.
*/
protected D putSeenData(V vertex, D data)
{
return seen.put(vertex, data);
}
/**
* Called when a vertex has been finished (meaning is dependent on traversal
* represented by subclass).
*
* @param vertex vertex which has been finished
*/
protected void finishVertex(V vertex)
{
fireVertexFinished(createVertexTraversalEvent(vertex));
}
// -------------------------------------------------------------------------
/**
* @param
* @param
* @param g
*
* @return TODO Document me
*/
static Specifics createGraphSpecifics(Graph g)
{
if (g instanceof DirectedGraph) {
return new DirectedSpecifics((DirectedGraph) g);
} else {
return new UndirectedSpecifics(g);
}
}
private void addUnseenChildrenOf(V vertex)
{
for (E edge : specifics.edgesOf(vertex)) {
fireEdgeTraversed(createEdgeTraversalEvent(edge));
V oppositeV = Graphs.getOppositeVertex(graph, edge, vertex);
if (isSeenVertex(oppositeV)) {
encounterVertexAgain(oppositeV, edge);
} else {
encounterVertex(oppositeV, edge);
}
}
}
private EdgeTraversalEvent createEdgeTraversalEvent(E edge)
{
if (isReuseEvents()) {
reusableEdgeEvent.setEdge(edge);
return reusableEdgeEvent;
} else {
return new EdgeTraversalEvent(this, edge);
}
}
private VertexTraversalEvent createVertexTraversalEvent(V vertex)
{
if (isReuseEvents()) {
reusableVertexEvent.setVertex(vertex);
return reusableVertexEvent;
} else {
return new VertexTraversalEvent(this, vertex);
}
}
private void encounterStartVertex()
{
encounterVertex(startVertex, null);
startVertex = null;
}
//~ Inner Interfaces -------------------------------------------------------
static interface SimpleContainer
{
/**
* Tests if this container is empty.
*
* @return true
if empty, otherwise false
.
*/
public boolean isEmpty();
/**
* Adds the specified object to this container.
*
* @param o the object to be added.
*/
public void add(T o);
/**
* Remove an object from this container and return it.
*
* @return the object removed from this container.
*/
public T remove();
}
//~ Inner Classes ----------------------------------------------------------
/**
* Provides unified interface for operations that are different in directed
* graphs and in undirected graphs.
*/
abstract static class Specifics
{
/**
* Returns the edges outgoing from the specified vertex in case of
* directed graph, and the edge touching the specified vertex in case of
* undirected graph.
*
* @param vertex the vertex whose outgoing edges are to be returned.
*
* @return the edges outgoing from the specified vertex in case of
* directed graph, and the edge touching the specified vertex in case of
* undirected graph.
*/
public abstract Set extends EE> edgesOf(VV vertex);
}
/**
* A reusable edge event.
*
* @author Barak Naveh
* @since Aug 11, 2003
*/
static class FlyweightEdgeEvent
extends EdgeTraversalEvent
{
private static final long serialVersionUID = 4051327833765000755L;
/**
* @see EdgeTraversalEvent#EdgeTraversalEvent(Object, Edge)
*/
public FlyweightEdgeEvent(Object eventSource, localE edge)
{
super(eventSource, edge);
}
/**
* Sets the edge of this event.
*
* @param edge the edge to be set.
*/
protected void setEdge(localE edge)
{
this.edge = edge;
}
}
/**
* A reusable vertex event.
*
* @author Barak Naveh
* @since Aug 11, 2003
*/
static class FlyweightVertexEvent
extends VertexTraversalEvent
{
private static final long serialVersionUID = 3834024753848399924L;
/**
* @see VertexTraversalEvent#VertexTraversalEvent(Object, Object)
*/
public FlyweightVertexEvent(Object eventSource, VV vertex)
{
super(eventSource, vertex);
}
/**
* Sets the vertex of this event.
*
* @param vertex the vertex to be set.
*/
protected void setVertex(VV vertex)
{
this.vertex = vertex;
}
}
/**
* An implementation of {@link Specifics} for a directed graph.
*/
private static class DirectedSpecifics
extends Specifics
{
private DirectedGraph graph;
/**
* Creates a new DirectedSpecifics object.
*
* @param g the graph for which this specifics object to be created.
*/
public DirectedSpecifics(DirectedGraph g)
{
graph = g;
}
/**
* @see CrossComponentIterator.Specifics#edgesOf(Object)
*/
public Set extends EE> edgesOf(VV vertex)
{
return graph.outgoingEdgesOf(vertex);
}
}
/**
* An implementation of {@link Specifics} in which edge direction (if any)
* is ignored.
*/
private static class UndirectedSpecifics
extends Specifics
{
private Graph graph;
/**
* Creates a new UndirectedSpecifics object.
*
* @param g the graph for which this specifics object to be created.
*/
public UndirectedSpecifics(Graph g)
{
graph = g;
}
/**
* @see CrossComponentIterator.Specifics#edgesOf(Object)
*/
public Set edgesOf(VV vertex)
{
return graph.edgesOf(vertex);
}
}
}
// End CrossComponentIterator.java