/* * EuroCarbDB, a framework for carbohydrate bioinformatics * * Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * A copy of this license accompanies this distribution in the file LICENSE.txt. * * This program 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. * * Last commit: $Rev: 1210 $ by $Author: glycoslave $ on $Date:: 2009-06-12 #$ */ package org.eurocarbdb.util.graph; import java.util.Set; import java.util.HashSet; import java.util.List; import java.util.ArrayList; import java.util.LinkedList; import java.util.Iterator; import org.eurocarbdb.util.graph.Graph; import org.eurocarbdb.util.graph.Edge; import org.eurocarbdb.util.graph.Vertex; /* abstract class Iterator *//********************************* * * Abstract base class for iterators over graphs. * * This class provides the regular Iterator semantics, but with * added functionality. * * @author matt * */ public abstract class GraphIterator<E,V> implements java.util.Iterator, Iterable { //~~~~~~~~~~~~~~~~~~~~~~~~ FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~~// /** The graph over which we're iterating. */ protected Graph<E,V> graph; /** List of unvisited vertices. This list may be used as either a * stack or queue, depending on the type of iteration. In a * depth-first algorithm, this list would be a stack, in a * breadth-first algorithm, this list would be a queue. */ protected LinkedList<Vertex<E,V>> unvisited; /** Stack of visited vertices. */ protected Set<Vertex<E,V>> visited; /** */ protected Vertex<E,V> startVertex; //~~~~~~~~~~~~~~~~~~~~~~ CONSTRUCTORS ~~~~~~~~~~~~~~~~~~~~~~~// /* Constructor *//***************************************** * * Constructs an iterator over the given graph, starting at the given * vertex. */ public GraphIterator( Graph<E,V> g, Vertex<E,V> start_vertex ) { assert g != null; assert start_vertex != null; this.graph = g; if ( ! graph.contains( start_vertex ) ) throw new RuntimeException( "Start vertex '" + start_vertex + "' does not exist in given graph" ); _init( start_vertex ); } //~~~~~~~~~~~~~~~~~~~~~~~~ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~// /* getValues *//******************************************* * * Returns a List of the remaining vertex values in the present iteration. * If none of the <tt>next*</tt> methods have been called then this * method will return all vertex values in the graph, in iteration order. */ public List<V> getValues() { List<V> list = new ArrayList<V>( graph.countVertices() ); while ( hasNext() ) list.add( next() ); return list; } /* getVertices *//***************************************** * * Returns a List of the remaining vertices in the present iteration. * If none of the <tt>next*</tt> methods have been called then this * method will return all vertices in the graph, in iteration order. */ public List<Vertex<E,V>> getVertices() { List<Vertex<E,V>> list = new ArrayList<Vertex<E,V>>( graph.countVertices() ); while ( this.hasNext() ) list.add( this.nextVertex() ); return list; } /* getCurrentVertex *//**************************************** * * Returns the current vertex in the present iteration. Does not advance * the iteration cursor. */ public Vertex<E,V> getCurrentVertex() { return unvisited.peek(); } /** Returns the graph over which we're iterating. */ public Graph<E,V> getGraph() { return graph; } /* @see java.util.Iterator#hasNext() */ public boolean hasNext() { return ! ( unvisited.isEmpty() || visited.size() >= graph.countVertices() ); } /* _init *//*************************************************** * * Initialises internal data prior to iteration. Can also be used to * re_initialise iteration to the starting state. */ private final void _init( Vertex<E,V> start_vertex ) { this.visited = new HashSet<Vertex<E,V>>( graph.countVertices() ); this.unvisited = new LinkedList<Vertex<E,V>>(); this.startVertex = start_vertex; pushUnvisited( start_vertex ); } /** Returns this iterator, so that these iterators can be used * in foreach statements. */ public Iterator iterator() { return this; } /* @see java.util.Iterator#next() */ public V next() { return nextVertex().getValue(); } /* nextVertex *//********************************************** * * Similar to <tt>next()</tt>, except that this method returns the * current vertex, instead of its value. Like <tt>next()</tt>, this * method advances the iteration cursor. */ public Vertex<E,V> nextVertex() { assert unvisited.size() > 0; Vertex<E,V> current = unvisited.remove(); if ( visited.contains( current ) ) return nextVertex(); visited.add( current ); if ( ! current.hasAttachedVertices() ) return current; for ( Vertex<E,V> child : current.getAttachedVertices() ) if ( ! visited.contains( child ) ) pushUnvisited( child ); return current; } /* pushUnvisited *//******************************************* * * Add a vertex to the 'unvisited' list. This method needs to be abstract * so that subclasses implementing depth-first or breadth-first algorithms * can add the passed vertex to the appropriate end of their stack or queue * respectively. This method would not be necessary if Java provided * Stack and Queue classes with common addition/removal semantics. * * @see #unvisited */ protected abstract void pushUnvisited( Vertex<E,V> v ); /* @see java.util.Iterator#remove() */ public void remove() { Vertex<E,V> v = unvisited.remove(); getGraph().remove( v ); } /** Resets iteration to when this iterator was first created. */ public void reset() { _init( this.startVertex ); } //~~~~~~~~~~~~~~~~~~~~~ INNER CLASSES ~~~~~~~~~~~~~~~~~~~~~~~// /* class GraphIterator.BreadthFirst *//************************ *<p> * Implements iteration through Graph vertices in breadth-first order. * This means that all of the vertices immediately attached to the current * vertex will be returned before any of their children are returned. *</p> *<p> * eg, given: *<pre> * * F * \ * E -- C * / \ * G B -- A * / * H -- D * *</pre> *<p> * If the starting vertex was A, the returned list would be: A, B, C, D, E, H, F, G. *</p> * Created 19-Oct-2005. * @author matt */ public static class BreadthFirst<E,V> extends GraphIterator<E,V> { /* Constructor */ public BreadthFirst( Graph<E,V> g, Vertex<E,V> start_vertex ) { super( g, start_vertex ); } /* @see GraphIterator#pushUnvisited(Vertex) */ protected void pushUnvisited( Vertex<E,V> v ) { unvisited.addLast( v ); } } /* class GraphIterator.DepthFirst *//************************** *<p> * Implements iteration through Graph vertices in depth-first order. * This means that all of the residues attached to a certain branch * will be returned before objects comprising other (sibling) branches. *</p> *<p> * eg, given: *<pre> * * F * \ * E -- C * / \ * G B -- A * / * H -- D * *</pre> *<p> * If the starting vertex was A, the returned list would be: A, B, C, E, F, G, D, H. *</p> * Created 19-Oct-2005. * @author matt */ public static class DepthFirst<E,V> extends GraphIterator<E,V> { /* Constructor */ public DepthFirst( Graph<E,V> g, Vertex<E,V> start_vertex ) { super( g, start_vertex ); } /* @see GraphIterator#pushUnvisited(Vertex) */ protected void pushUnvisited( Vertex<E,V> v ) { unvisited.addFirst( v ); } } } // end of class Iterator