Review this code regarding optimization, cleanup, and best practices.
final class EdgePrims<T> {
private final T source, target;
private final int distance;
public EdgePrims(T node1, T node2, int distance) {
this.source = node1;
this.target = node2;
this.distance = distance;
}
public T getSource() {
return source;
}
public T getTarget() {
return target;
}
public int getDistance() {
return distance;
}
@Override
public String toString() {
return " first vertex " + source + " to vertex " + target + " with distance: " + distance;
}
}
final class GraphPrims<T> implements Iterable<T> {
private final Map<T, Map<T, Integer>> graph;
public GraphPrims() {
graph = new HashMap<T, Map<T, Integer>>();
}
public void addEgde(T vertex1, T vertex2, int distance) {
if (vertex1 == null) {
throw new NullPointerException("The vertex 1 cannot be null");
}
if (vertex2 == null) {
throw new NullPointerException("The vertex 2 cannot be null");
}
if (!graph.containsKey(vertex1)) {
graph.put(vertex1, new HashMap<T, Integer>());
}
if (!graph.containsKey(vertex2)) {
graph.put(vertex2, new HashMap<T, Integer>());
}
graph.get(vertex1).put(vertex2, distance);
graph.get(vertex2).put(vertex1, distance);
}
public Set<T> getVertices() {
return Collections.unmodifiableSet(graph.keySet()); // QQ: should this be replaced by DEEP COPy ?
}
public Map<T, Integer> getEdges(T source) {
if (source == null) {
throw new NullPointerException("The source cannot be null.");
}
return Collections.unmodifiableMap(graph.get(source));
}
public void removeEdges(T vertex1, T vertex2) {
if (vertex1 == null) {
throw new NullPointerException("The vertex 1 cannot be null");
}
if (vertex2 == null) {
throw new NullPointerException("The vertex 2 cannot be null");
}
if (!graph.containsKey(vertex1)) {
throw new NoSuchElementException("vertex " + vertex1 + " does not exist.");
}
if (!graph.containsKey(vertex2)) {
throw new NoSuchElementException("vertex " + vertex2 + " does not exist.");
}
graph.get(vertex1).remove(vertex2);
graph.get(vertex2).remove(vertex1);
}
@Override
public Iterator<T> iterator() {
return graph.keySet().iterator();
}
}
public class Prims<T> {
public static Comparator<EdgePrims> edgeComparator = new Comparator<EdgePrims>() {
@Override
public int compare(EdgePrims edge1, EdgePrims edge2) {
return edge1.getDistance() - edge2.getDistance();
}
};
/**
* Uses prim's algo to calculate a MST for a connected graph.
* A non-connected graph will lead to unpredictable result.
*
* @param graph a connected graph.
* @return a list of edges that constitute the MST
*/
public static <T> List<EdgePrims<T>> getMinSpanTree(GraphPrims<T> graph) {
Queue<EdgePrims<T>> edgesAvailable = new PriorityQueue<EdgePrims<T>>(10, edgeComparator);
List<EdgePrims<T>> listMinEdges = new ArrayList<EdgePrims<T>>();
Set<T> unvisitedVertices = new HashSet<T>();
unvisitedVertices.addAll(graph.getVertices());
T sourceVertex = unvisitedVertices.iterator().next();
unvisitedVertices.remove(sourceVertex);
while (!unvisitedVertices.isEmpty()) {
/* populate all edges for the current vertex */
for (Entry<T, Integer> e : graph.getEdges(sourceVertex).entrySet()) {
/* dont add a duplicate edge */
if (unvisitedVertices.contains(e.getKey())) {
edgesAvailable.add(new EdgePrims(sourceVertex, e.getKey(), (Integer) e.getValue()));
}
}
/* fetch the edge with least distance */
EdgePrims<T> minEdge = edgesAvailable.poll();
/* if the target is already visited then move to next edge */
while (!unvisitedVertices.contains(minEdge.getTarget())) {
minEdge = edgesAvailable.poll();
}
listMinEdges.add(minEdge); // this list will contain unique targetvertices.
sourceVertex = minEdge.getTarget(); // get the next vertex.
unvisitedVertices.remove(sourceVertex);
}
return listMinEdges;
}
public static void main(String[] args) {
GraphPrims<Character> graphPrims = new GraphPrims<Character>();
graphPrims.addEgde('A', 'B', 10);
graphPrims.addEgde('A', 'C', 15);
graphPrims.addEgde('C', 'B', 50);
graphPrims.addEgde('C', 'D', 20);
graphPrims.addEgde('B', 'D', 80);
graphPrims.addEgde('B', 'F', 80);
// graphPrims.addEgde('x', 'y', 700);
for (EdgePrims<Character> edge : getMinSpanTree(graphPrims)) {
System.out.println(edge.toString());
}
}
}