All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.traverse.TopologicalOrderIterator 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.
 */
/* -----------------------------
 * TopologicalOrderIterator.java
 * -----------------------------
 * (C) Copyright 2004-2008, by Marden Neubert and Contributors.
 *
 * Original Author:  Marden Neubert
 * Contributor(s):   Barak Naveh, John V. Sichi
 *
 * $Id$
 *
 * Changes
 * -------
 * 17-Dec-2004 : Initial revision (MN);
 * 25-Apr-2005 : Fixes for start vertex order (JVS);
 * 06-Jun-2005 : Made generic (CH);
 *
 */
package org.jgrapht.traverse;

import java.util.*;

import org.jgrapht.*;
import org.jgrapht.util.*;


/**
 * Implements topological order traversal for a directed acyclic graph. A
 * topological sort is a permutation p of the vertices of a graph such
 * that an edge (i,j) implies that i appears before j
 * in p (Skiena 1990, p. 208). See also 
 * http://mathworld.wolfram.com/TopologicalSort.html.
 *
 * 

See "Algorithms in Java, Third Edition, Part 5: Graph Algorithms" by * Robert Sedgewick and "Data Structures and Algorithms with Object-Oriented * Design Patterns in Java" by Bruno R. Preiss for implementation alternatives. * The latter can be found online at * http://www.brpreiss.com/books/opus5/

* *

For this iterator to work correctly the graph must be acyclic, and must * not be modified during iteration. Currently there are no means to ensure * that, nor to fail-fast; the results with cyclic input (including self-loops) * or concurrent modifications are undefined. To precheck a graph for cycles, * consider using {@link org.jgrapht.alg.CycleDetector} or {@link * org.jgrapht.alg.StrongConnectivityInspector}.

* * @author Marden Neubert * @since Dec 18, 2004 */ public class TopologicalOrderIterator extends CrossComponentIterator { private Queue queue; private Map inDegreeMap; /** * Creates a new topological order iterator over the directed graph * specified, with arbitrary tie-breaking in case of partial order. * Traversal will start at one of the graph's sources. See the * definition of source at * http://mathworld.wolfram.com/Source.html. * * @param dg the directed graph to be iterated. */ public TopologicalOrderIterator(DirectedGraph dg) { this(dg, new LinkedListQueue()); } /** * Creates a new topological order iterator over the directed graph * specified, with a user-supplied queue implementation to allow customized * control over tie-breaking in case of partial order. Traversal will start * at one of the graph's sources. See the definition of source at * http://mathworld.wolfram.com/Source.html. * * @param dg the directed graph to be iterated. * @param queue queue to use for tie-break in case of partial order (e.g. a * PriorityQueue can be used to break ties according to vertex priority); * must be initially empty */ public TopologicalOrderIterator(DirectedGraph dg, Queue queue) { this(dg, queue, new HashMap()); } // NOTE: This is a hack to deal with the fact that CrossComponentIterator // needs to know the start vertex in its constructor private TopologicalOrderIterator( DirectedGraph dg, Queue queue, Map inDegreeMap) { this(dg, initialize(dg, queue, inDegreeMap)); this.queue = queue; this.inDegreeMap = inDegreeMap; // empty queue for non-empty graph would indicate presence of // cycles (no roots found) assert dg.vertexSet().isEmpty() || !queue.isEmpty(); } // NOTE: This is intentionally private, because starting the sort "in the // middle" doesn't make sense. private TopologicalOrderIterator(DirectedGraph dg, V start) { super(dg, start); } /** * @see CrossComponentIterator#isConnectedComponentExhausted() */ @Override protected boolean isConnectedComponentExhausted() { // FIXME jvs 25-Apr-2005: This isn't correct for a graph with more than // one component. We will actually exhaust a connected component // before the queue is empty, because initialize adds roots from all // components to the queue. return queue.isEmpty(); } /** * @see CrossComponentIterator#encounterVertex(Object, Object) */ @Override protected void encounterVertex(V vertex, E edge) { putSeenData(vertex, null); decrementInDegree(vertex); } /** * @see CrossComponentIterator#encounterVertexAgain(Object, Object) */ @Override protected void encounterVertexAgain(V vertex, E edge) { decrementInDegree(vertex); } /** * @see CrossComponentIterator#provideNextVertex() */ @Override protected V provideNextVertex() { return queue.remove(); } /** * Decrements the in-degree of a vertex. * * @param vertex the vertex whose in-degree will be decremented. */ private void decrementInDegree(V vertex) { ModifiableInteger inDegree = inDegreeMap.get(vertex); if (inDegree.value > 0) { inDegree.value--; if (inDegree.value == 0) { queue.offer(vertex); } } } /** * Initializes the internal traversal object structure. Sets up the internal * queue with the directed graph vertices and creates the control structure * for the in-degrees. * * @param dg the directed graph to be iterated. * @param queue initializer for queue * @param inDegreeMap initializer for inDegreeMap * * @return start vertex */ private static V initialize( DirectedGraph dg, Queue queue, Map inDegreeMap) { for (Iterator i = dg.vertexSet().iterator(); i.hasNext();) { V vertex = i.next(); int inDegree = dg.inDegreeOf(vertex); inDegreeMap.put(vertex, new ModifiableInteger(inDegree)); if (inDegree == 0) { queue.offer(vertex); } } if (queue.isEmpty()) { return null; } else { return queue.peek(); } } // NOTE jvs 22-Dec-2006: For JDK1.4-compatibility, we can't assume // that LinkedList implements Queue, since that wasn't introduced // until JDK1.5, so use an adapter here. Move this to // top-level in org.jgrapht.util if anyone else needs it. private static class LinkedListQueue extends LinkedList implements Queue { private static final long serialVersionUID = 4217659843476891334L; @Override public T element() { return getFirst(); } @Override public boolean offer(T o) { return add(o); } @Override public T peek() { if (isEmpty()) { return null; } return getFirst(); } @Override public T poll() { if (isEmpty()) { return null; } return removeFirst(); } @Override public T remove() { return removeFirst(); } } } // End TopologicalOrderIterator.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy