/* ========================================== * 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. */ /* --------------------------- * CrossComponentIterator.java * --------------------------- * (C) Copyright 2003-2008, by Barak Naveh and Contributors. * * Original Author: Barak Naveh * Contributor(s): John V. Sichi * Christian Hammer * * $Id$ * * 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<Edge> to Set<Edge> (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 <V> vertex type * @param <E> edge type * @param <D> type of data associated to seen vertices * * @author Barak Naveh * @since Jan 31, 2004 */ public abstract class CrossComponentIterator<V, E, D> extends AbstractGraphIterator<V, E> { private static final int CCS_BEFORE_COMPONENT = 1; private static final int CCS_WITHIN_COMPONENT = 2; private static final int CCS_AFTER_COMPONENT = 3; /** * 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 } // 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<V, E> reusableEdgeEvent; private FlyweightVertexEvent<V> reusableVertexEvent; private Iterator<V> vertexIterator = null; /** * Stores the vertices that have been seen during iteration and (optionally) * some additional traversal info regarding each vertex. */ private Map<V, D> seen = new HashMap<V, D>(); private V startVertex; private Specifics<V, E> specifics; private final Graph<V, E> graph; /** * The connected component state */ private int state = CCS_BEFORE_COMPONENT; /** * Creates a new iterator for the specified graph. Iteration will start at * the specified start vertex. If the specified start vertex is <code> * null</code>, 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 <code>g==null</code> or does not * contain <code>startVertex</code> */ public CrossComponentIterator(Graph<V, E> 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<V, E>(this, null); reusableVertexEvent = new FlyweightVertexEvent<V>(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"); } } /** * @return the graph being traversed */ public Graph<V, E> 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; if (nListeners != 0) { 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; if (nListeners != 0) { fireConnectedComponentStarted(ccStartedEvent); } } V nextVertex = provideNextVertex(); if (nListeners != 0) { fireVertexTraversed(createVertexTraversalEvent(nextVertex)); } addUnseenChildrenOf(nextVertex); return nextVertex; } else { throw new NoSuchElementException(); } } /** * Returns <tt>true</tt> if there are no more uniterated vertices in the * currently iterated connected component; <tt>false</tt> otherwise. * * @return <tt>true</tt> if there are no more uniterated vertices in the * currently iterated connected component; <tt>false</tt> 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 * <code>next</code> 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 <code>null</code> if no * data was associated with the vertex. A <code>null</code> return can also * indicate that the vertex was explicitly associated with <code> * null</code>. */ 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 <tt>true</tt> 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 <code> * null</code> if no data was associated with the vertex. A <code> * null</code> return can also indicate that the vertex was explicitly * associated with <code>null</code>. */ 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) { if (nListeners != 0) { fireVertexFinished(createVertexTraversalEvent(vertex)); } } // ------------------------------------------------------------------------- /** * @param <V> * @param <E> * @param g * * @return TODO Document me */ static <V, E> Specifics<V, E> createGraphSpecifics(Graph<V, E> g) { if (g instanceof DirectedGraph<?, ?>) { return new DirectedSpecifics<V, E>((DirectedGraph<V, E>) g); } else { return new UndirectedSpecifics<V, E>(g); } } private void addUnseenChildrenOf(V vertex) { for (E edge : specifics.edgesOf(vertex)) { if (nListeners != 0) { fireEdgeTraversed(createEdgeTraversalEvent(edge)); } V oppositeV = Graphs.getOppositeVertex(graph, edge, vertex); if (isSeenVertex(oppositeV)) { encounterVertexAgain(oppositeV, edge); } else { encounterVertex(oppositeV, edge); } } } private EdgeTraversalEvent<V, E> createEdgeTraversalEvent(E edge) { if (isReuseEvents()) { reusableEdgeEvent.setEdge(edge); return reusableEdgeEvent; } else { return new EdgeTraversalEvent<V, E>(this, edge); } } private VertexTraversalEvent<V> createVertexTraversalEvent(V vertex) { if (isReuseEvents()) { reusableVertexEvent.setVertex(vertex); return reusableVertexEvent; } else { return new VertexTraversalEvent<V>(this, vertex); } } private void encounterStartVertex() { encounterVertex(startVertex, null); startVertex = null; } static interface SimpleContainer<T> { /** * Tests if this container is empty. * * @return <code>true</code> if empty, otherwise <code>false</code>. */ 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(); } /** * Provides unified interface for operations that are different in directed * graphs and in undirected graphs. */ abstract static class Specifics<VV, EE> { /** * 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<VV, localE> extends EdgeTraversalEvent<VV, localE> { 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<VV> extends VertexTraversalEvent<VV> { 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<VV, EE> extends Specifics<VV, EE> { private DirectedGraph<VV, EE> graph; /** * Creates a new DirectedSpecifics object. * * @param g the graph for which this specifics object to be created. */ public DirectedSpecifics(DirectedGraph<VV, EE> 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<VV, EE> extends Specifics<VV, EE> { private Graph<VV, EE> graph; /** * Creates a new UndirectedSpecifics object. * * @param g the graph for which this specifics object to be created. */ public UndirectedSpecifics(Graph<VV, EE> g) { graph = g; } /** * @see CrossComponentIterator.Specifics#edgesOf(Object) */ public Set<EE> edgesOf(VV vertex) { return graph.edgesOf(vertex); } } } // End CrossComponentIterator.java