package com.pahimar.ee3.emc.graph; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Logger; public class WeightedDirectedGraph implements Iterable { private final Map>> graph = new HashMap>>(); private List orderedNodes = new ArrayList(); public boolean addNode(T node) { // Ignore nodes already added if (graph.containsKey(node)) return false; orderedNodes.add(node); graph.put(node, new TreeSet>(new Comparator>() { @Override public int compare(WeightedEdge o1, WeightedEdge o2) { return orderedNodes.indexOf(o1.getTarget()) - orderedNodes.indexOf(o2.getTarget()); } })); return true; } public void addEdge(T from, T to) { addEdge(from, to, 1); } public void addEdge(T from, T to, float weight) { if (!(graph.containsKey(from) && graph.containsKey(to))) { if (!graph.containsKey(from)) { LOGGER.severe("From node doesn't exist: " + from.toString()); } if (!graph.containsKey(to)) { LOGGER.severe("To node doesn't exist: " + to.toString()); } throw new NoSuchElementException("Missing nodes from graph"); } // If a directed edge of the same weight doesn't already exist, add the new edge if (!edgeExists(from, to, weight)) { graph.get(from).add(new WeightedEdge(weight, to)); } } public boolean edgeExists(T from, T to) { if (!(graph.containsKey(from) && graph.containsKey(to))) throw new NoSuchElementException("Missing nodes from graph"); Iterator> edgeIterator = graph.get(from).iterator(); while (edgeIterator.hasNext()) { if (edgeIterator.next().getTarget().equals(to)) return true; } return false; } public boolean edgeExists(T from, T to, float weight) { if (!(graph.containsKey(from) && graph.containsKey(to))) { if (!graph.containsKey(from)) { LOGGER.severe("From node doesn't exist: " + from.toString()); LOGGER.severe("To node: " + to.toString()); } if (!graph.containsKey(to)) { LOGGER.severe("To node doesn't exist: " + to.toString()); LOGGER.severe("From node: " + from.toString()); } throw new NoSuchElementException("Missing nodes from graph"); } return graph.get(from).contains(new WeightedEdge(weight, to)); } public boolean nodeExists(T node) { return graph.containsKey(node); } public Set> edgesFrom(T from) { if (!graph.containsKey(from)) throw new NoSuchElementException("Missing node from graph"); return Collections.unmodifiableSortedSet(graph.get(from)); } public Set> edgesTo(T to) { if (!graph.containsKey(to)) throw new NoSuchElementException("Missing node from graph"); Set> edgesTo = new TreeSet>(new Comparator>() { @Override public int compare(WeightedEdge o1, WeightedEdge o2) { return o1.hashCode() - o2.hashCode(); } }); for (T node : graph.keySet()) { if (!node.equals(to)) { Set> edgesFrom = edgesFrom(node); for (WeightedEdge fromEdge : edgesFrom) { if (fromEdge.getTarget().equals(to)) { edgesTo.add(new WeightedEdge(fromEdge.getWeight(), node)); } } } } return Collections.unmodifiableSet(edgesTo); } public void removeNode(T node) { if (!graph.containsKey(node)) throw new NoSuchElementException("Missing node from graph"); // Remove all edges from and to the node removeAllEdgesFrom(node); removeAllEdgesTo(node); // Remove the node graph.remove(node); } public void removeEdge(T from, T to) { removeEdge(from, to, 1); } public void removeEdge(T from, T to, float weight) { if (!(graph.containsKey(from) && graph.containsKey(to))) throw new NoSuchElementException("Missing nodes from graph"); graph.get(from).remove(new WeightedEdge(weight, to)); } public void removeAllEdgesFrom(T node) { if (!graph.containsKey(node)) throw new NoSuchElementException("Missing node from graph"); graph.get(node).clear(); } public void removeAllEdgesTo(T node) { if (!graph.containsKey(node)) throw new NoSuchElementException("Missing node from graph"); for (T aNode : graph.keySet()) { Set> edgesFrom = edgesFrom(aNode); for (WeightedEdge fromEdge : edgesFrom) { if (fromEdge.getTarget().equals(node)) { graph.get(aNode).remove(fromEdge); } } } } public void removeAllEdgesBetween(T firstNode, T secondNode) { if (!(graph.containsKey(firstNode) && graph.containsKey(secondNode))) throw new NoSuchElementException("Missing nodes from graph"); for (WeightedEdge edgeFrom : edgesFrom(firstNode)) { if (edgeFrom.getTarget().equals(secondNode)) { graph.get(firstNode).remove(edgeFrom); } } for (WeightedEdge edgeFrom : edgesFrom(secondNode)) { if (edgeFrom.getTarget().equals(firstNode)) { graph.get(secondNode).remove(edgeFrom); } } } public List getAllNodes() { return orderedNodes; } public List getCriticalNodes() { ArrayList criticalNodes = new ArrayList(); Iterator nodeIter = orderedNodes.iterator(); while (nodeIter.hasNext()) { T currentNode = nodeIter.next(); if (this.edgesFrom(currentNode).size() == 0) { criticalNodes.add(currentNode); } } return criticalNodes; } public List getOrphanNodes() { ArrayList orphanedNodes = new ArrayList(); Iterator nodeIter = orderedNodes.iterator(); while (nodeIter.hasNext()) { T currentNode = nodeIter.next(); if (this.edgesFrom(currentNode).size() == 0 && this.edgesTo(currentNode).size() == 0) { orphanedNodes.add(currentNode); } } return orphanedNodes; } @Override public Iterator iterator() { return orderedNodes.iterator(); } public int size() { return graph.size(); } public boolean isEmpty() { return graph.isEmpty(); } @Override public String toString() { return graph.toString(); } private static final Logger LOGGER = Logger.getLogger(WeightedDirectedGraph.class.getName()); }