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 the vertex type * @param the edge type */ @SuppressWarnings("unchecked") public class PrimMinimumSpanningTree implements Transformer,Graph> { protected Factory> treeFactory; protected Transformer weights; /** * Creates an instance which generates a minimum spanning tree assuming constant edge weights. */ public PrimMinimumSpanningTree(Factory> factory) { this(factory, new ConstantTransformer(1.0)); } /** * Creates an instance which generates a minimum spanning tree using the input edge weights. */ public PrimMinimumSpanningTree(Factory> factory, Transformer weights) { this.treeFactory = factory; if(weights != null) { this.weights = weights; } } /** * @param graph the Graph to find MST in */ public Graph transform(Graph graph) { Set unfinishedEdges = new HashSet(graph.getEdges()); Graph 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 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 tree, Graph graph, Collection unfinishedEdges) { Collection 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 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); } } }