package edu.uci.ics.jung.algorithms.shortestpath; import java.util.Collection; import java.util.HashSet; 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.graph.Graph; import edu.uci.ics.jung.graph.util.Pair; /** * For the input Graph, creates a MinimumSpanningTree using a variation of * Prim's algorithm. * * @author Tom Nelson - tomnelson@dev.java.net * * @param <V> * the vertex type * @param <E> * the edge type */ @SuppressWarnings("unchecked") public class PrimMinimumSpanningTree<V, E> implements Transformer<Graph<V, E>, Graph<V, E>> { protected Factory<? extends Graph<V, E>> treeFactory; protected Transformer<E, Double> weights; /** * Creates an instance which generates a minimum spanning tree assuming * constant edge weights. */ public PrimMinimumSpanningTree(Factory<? extends Graph<V, E>> factory) { this(factory, new ConstantTransformer(1.0)); } /** * Creates an instance which generates a minimum spanning tree using the * input edge weights. */ public PrimMinimumSpanningTree(Factory<? extends Graph<V, E>> factory, Transformer<E, Double> weights) { this.treeFactory = factory; if (weights != null) { this.weights = weights; } } /** * @param graph * the Graph to find MST in */ @Override public Graph<V, E> transform(Graph<V, E> graph) { Set<E> unfinishedEdges = new HashSet<E>(graph.getEdges()); Graph<V, E> tree = treeFactory.create(); V root = findRoot(graph); if (graph.getVertices().contains(root)) { tree.addVertex(root); } else if (graph.getVertexCount() > 0) { // pick an arbitrary vertex to make root tree.addVertex(graph.getVertices().iterator().next()); } updateTree(tree, graph, unfinishedEdges); return tree; } protected V findRoot(Graph<V, E> graph) { for (V v : graph.getVertices()) { if (graph.getInEdges(v).size() == 0) { return v; } } // if there is no obvious root, pick any vertex if (graph.getVertexCount() > 0) { return graph.getVertices().iterator().next(); } // this graph has no vertices return null; } protected void updateTree(Graph<V, E> tree, Graph<V, E> graph, Collection<E> unfinishedEdges) { Collection<V> tv = tree.getVertices(); double minCost = Double.MAX_VALUE; E nextEdge = null; V nextVertex = null; V currentVertex = null; for (E e : unfinishedEdges) { if (tree.getEdges().contains(e)) { continue; } // find the lowest cost edge, get its opposite endpoint, // and then update forest from its Successors Pair<V> endpoints = graph.getEndpoints(e); V first = endpoints.getFirst(); V second = endpoints.getSecond(); if ((tv.contains(first) == true && tv.contains(second) == false)) { if (weights.transform(e) < minCost) { minCost = weights.transform(e); nextEdge = e; currentVertex = first; nextVertex = second; } } else if ((tv.contains(second) == true && tv.contains(first) == false)) { if (weights.transform(e) < minCost) { minCost = weights.transform(e); nextEdge = e; currentVertex = second; nextVertex = first; } } } if (nextVertex != null && nextEdge != null) { unfinishedEdges.remove(nextEdge); tree.addEdge(nextEdge, currentVertex, nextVertex); updateTree(tree, graph, unfinishedEdges); } } }