View Javadoc
1   package edu.uci.ics.jung.algorithms.shortestpath;
2   
3   import java.util.Collection;
4   import java.util.Set;
5   
6   import com.google.common.base.Function;
7   import com.google.common.base.Functions;
8   import com.google.common.base.Supplier;
9   
10  import edu.uci.ics.jung.algorithms.cluster.WeakComponentClusterer;
11  import edu.uci.ics.jung.algorithms.filters.FilterUtils;
12  import edu.uci.ics.jung.graph.Forest;
13  import edu.uci.ics.jung.graph.Graph;
14  import edu.uci.ics.jung.graph.Tree;
15  import edu.uci.ics.jung.graph.util.TreeUtils;
16  
17  /**
18   * For the input Graph, creates a MinimumSpanningTree
19   * using a variation of Prim's algorithm.
20   * 
21   * @author Tom Nelson - tomnelson@dev.java.net
22   *
23   * @param <V> the vertex type
24   * @param <E> the edge type
25   */
26  @SuppressWarnings("unchecked")
27  public class MinimumSpanningForest2<V,E> {
28  	
29  	protected Graph<V,E> graph;
30  	protected Forest<V,E> forest;
31  	protected Function<? super E,Double> weights = 
32  		(Function<E,Double>)Functions.<Double>constant(1.0);
33  	
34  	/**
35  	 * Create a Forest from the supplied Graph and supplied Supplier, which
36  	 * is used to create a new, empty Forest. If non-null, the supplied root
37  	 * will be used as the root of the tree/forest. If the supplied root is
38  	 * null, or not present in the Graph, then an arbitary Graph vertex
39  	 * will be selected as the root.
40  	 * If the Minimum Spanning Tree does not include all vertices of the
41  	 * Graph, then a leftover vertex is selected as a root, and another
42  	 * tree is created
43  	 * @param graph the graph for which the minimum spanning forest will be generated
44  	 * @param supplier a factory for the type of forest to build
45  	 * @param treeFactory a factory for the type of tree to build
46  	 * @param weights edge weights; may be null
47  	 */
48  	public MinimumSpanningForest2(Graph<V, E> graph, 
49  			Supplier<Forest<V,E>> supplier, 
50  			Supplier<? extends Graph<V,E>> treeFactory,
51  			Function<? super E, Double> weights) {
52  		this(graph, supplier.get(), 
53  				treeFactory, 
54  				weights);
55  	}
56  	
57  	/**
58  	 * Create a forest from the supplied graph, populating the
59  	 * supplied Forest, which must be empty. 
60  	 * If the supplied root is null, or not present in the Graph,
61  	 * then an arbitary Graph vertex will be selected as the root.
62  	 * If the Minimum Spanning Tree does not include all vertices of the
63  	 * Graph, then a leftover vertex is selected as a root, and another
64  	 * tree is created
65  	 * @param graph the Graph to find MST in
66  	 * @param forest the Forest to populate. Must be empty
67  	 * @param treeFactory a factory for the type of tree to build
68  	 * @param weights edge weights, may be null
69  	 */
70  	public MinimumSpanningForest2(Graph<V, E> graph, 
71  			Forest<V,E> forest, 
72  			Supplier<? extends Graph<V,E>> treeFactory,
73  			Function<? super E, Double> weights) {
74  		
75  		if(forest.getVertexCount() != 0) {
76  			throw new IllegalArgumentException("Supplied Forest must be empty");
77  		}
78  		this.graph = graph;
79  		this.forest = forest;
80  		if(weights != null) {
81  			this.weights = weights;
82  		}
83  		
84  		WeakComponentClusterer<V,E> wcc =
85  			new WeakComponentClusterer<V,E>();
86  		Set<Set<V>> component_vertices = wcc.apply(graph);
87  		Collection<Graph<V,E>> components = 
88  			FilterUtils.createAllInducedSubgraphs(component_vertices, graph);
89  		
90  		for(Graph<V,E> component : components) {
91  			PrimMinimumSpanningTree<V,E> mst = 
92  				new PrimMinimumSpanningTree<V,E>(treeFactory, this.weights);
93  			Graph<V,E> subTree = mst.apply(component);
94  			if(subTree instanceof Tree) {
95  				TreeUtils.addSubTree(forest, (Tree<V,E>)subTree, null, null);
96  			}
97  		}
98  	}
99  	
100 	/**
101 	 * @return the generated forest
102 	 */
103 	public Forest<V,E> getForest() {
104 		return forest;
105 	}
106 }