package edu.uci.ics.jung.algorithms.shortestpath; import java.util.Collection; import java.util.Set; import org.apache.commons.collections15.Factory; import org.apache.commons.collections15.Transformer; import org.apache.commons.collections15.functors.ConstantTransformer; import edu.uci.ics.jung.algorithms.cluster.WeakComponentClusterer; import edu.uci.ics.jung.algorithms.filters.FilterUtils; import edu.uci.ics.jung.graph.Forest; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.Tree; import edu.uci.ics.jung.graph.util.TreeUtils; /** * For the input Graph, creates a MinimumSpanningTree using a variation of * Prim's algorithm. * * @author Tom Nelson - tomnelson@dev.java.net * * @param <V> * @param <E> */ @SuppressWarnings("unchecked") public class MinimumSpanningForest2<V, E> { protected Graph<V, E> graph; protected Forest<V, E> forest; protected Transformer<E, Double> weights = (Transformer<E, Double>) new ConstantTransformer<Double>( 1.0); /** * create a Forest from the supplied Graph and supplied Factory, which is * used to create a new, empty Forest. If non-null, the supplied root will * be used as the root of the tree/forest. If the supplied root is null, or * not present in the Graph, then an arbitary Graph vertex will be selected * as the root. If the Minimum Spanning Tree does not include all vertices * of the Graph, then a leftover vertex is selected as a root, and another * tree is created * * @param graph * @param factory * @param weights */ public MinimumSpanningForest2(Graph<V, E> graph, Factory<Forest<V, E>> factory, Factory<? extends Graph<V, E>> treeFactory, Transformer<E, Double> weights) { this(graph, factory.create(), treeFactory, weights); } /** * create a forest from the supplied graph, populating the supplied Forest, * which must be empty. If the supplied root is null, or not present in the * Graph, then an arbitary Graph vertex will be selected as the root. If the * Minimum Spanning Tree does not include all vertices of the Graph, then a * leftover vertex is selected as a root, and another tree is created * * @param graph * the Graph to find MST in * @param forest * the Forest to populate. Must be empty * @param weights * edge weights, may be null */ public MinimumSpanningForest2(Graph<V, E> graph, Forest<V, E> forest, Factory<? extends Graph<V, E>> treeFactory, Transformer<E, Double> weights) { if (forest.getVertexCount() != 0) { throw new IllegalArgumentException("Supplied Forest must be empty"); } this.graph = graph; this.forest = forest; if (weights != null) { this.weights = weights; } WeakComponentClusterer<V, E> wcc = new WeakComponentClusterer<V, E>(); Set<Set<V>> component_vertices = wcc.transform(graph); Collection<Graph<V, E>> components = FilterUtils .createAllInducedSubgraphs(component_vertices, graph); for (Graph<V, E> component : components) { PrimMinimumSpanningTree<V, E> mst = new PrimMinimumSpanningTree<V, E>( treeFactory, this.weights); Graph<V, E> subTree = mst.transform(component); if (subTree instanceof Tree) { TreeUtils.addSubTree(forest, (Tree<V, E>) subTree, null, null); } } } /** * Returns the generated forest. */ public Forest<V, E> getForest() { return forest; } }