package DirectedGraphJava; import java.util.HashSet; import java.util.HashMap; import java.util.Iterator; import java.util.Queue; import java.util.Set; import java.util.LinkedList; import java.util.ArrayList; import java.util.Collections; public class DirectedGraph implements IDirectedGraph { private HashSet _vertices = new HashSet(); private HashMap> _inbounds = new HashMap>(); private HashMap> _outbounds = new HashMap>(); private HashMap,Integer> _edges = new HashMap,Integer>(); public DirectedGraph() { //nothing to do } public DirectedGraph reindex(){ HashMap oldToNew = new HashMap(); int i = 0; for (Integer vertex : _vertices) { oldToNew.put(vertex,i); i++; } DirectedGraph newGraph = new DirectedGraph(); for (Integer vertex : _vertices) { newGraph.addVertex(oldToNew.get(vertex)); } for (Pair edge : _edges.keySet()) { newGraph.addEdge(oldToNew.get(edge.first),oldToNew.get(edge.second),_edges.get(edge)); } return newGraph; } public Integer numVertices() { return _vertices.size(); } public Integer numEdges() { return _edges.size(); } public Iterator vertices() { return _vertices.iterator(); } public Iterator,Integer>> edges() { HashSet,Integer>> keyValues = new HashSet,Integer>>(); for (Pair key : this._edges.keySet()) { Pair,Integer> keyValuePair = new Pair,Integer>(key,this._edges.get(key)); keyValues.add(keyValuePair); } return keyValues.iterator(); } public boolean isEdge(Integer v1, Integer v2) { if(!_vertices.contains(v1) || !_vertices.contains(v2)) { throw new IllegalArgumentException("Vertex does not exist"); } return _edges.containsKey(new Pair(v1,v2)); } public int inDegree(Integer v) { if(!_vertices.contains(v)) { throw new IllegalArgumentException("Vertex does not exist"); } return _inbounds.get(v).size(); } public int outDegree(Integer v) { if(!_vertices.contains(v)) { throw new IllegalArgumentException("Vertex does not exist"); } return _outbounds.get(v).size(); } public Iterator inbounds(Integer v) { if(!_vertices.contains(v)) { throw new IllegalArgumentException("Vertex does not exist"); } return _inbounds.get(v).iterator(); } public Iterator outbounds(Integer v) { if(!_vertices.contains(v)) { throw new IllegalArgumentException("Vertex does not exist"); } return _outbounds.get(v).iterator(); } public Integer weight(Integer v1, Integer v2) { if(!_vertices.contains(v1) || !_vertices.contains(v2)) { throw new IllegalArgumentException("Vertex does not exist"); } if(!_edges.containsKey(new Pair(v1,v2))) { throw new IllegalArgumentException("Edge does not exist"); } return _edges.get(new Pair(v1,v2)); } public void weight(Integer v1, Integer v2, Integer w) { if(!_vertices.contains(v1) || !_vertices.contains(v2)) { throw new IllegalArgumentException("Vertex does not exist"); } if(!_edges.containsKey(new Pair(v1,v2))) { throw new IllegalArgumentException("Edge does not exist"); } _edges.put(new Pair(v1,v2),w); } public void addVertex(Integer v) { if(_vertices.contains(v)) { throw new IllegalArgumentException("Vertex already exists"); } _vertices.add(v); _inbounds.put(v,new HashSet()); _outbounds.put(v,new HashSet()); } public void removeVertex(Integer v) { if(!_vertices.contains(v)) { throw new IllegalArgumentException("Vertex does not exist"); } _vertices.remove(v); for (Integer vertex : _inbounds.get(v)) { _outbounds.get(vertex).remove(v); _edges.remove(new Pair(vertex,v)); } for (Integer vertex : _outbounds.get(v)) { _inbounds.get(vertex).remove(v); _edges.remove(new Pair(v,vertex)); } _inbounds.remove(v); _outbounds.remove(v); } public void addEdge(Integer v1, Integer v2, Integer w) { if(!_vertices.contains(v1) || !_vertices.contains(v2)) { throw new IllegalArgumentException("Vertex does not exist"); } if(_edges.containsKey(new Pair(v1,v2))) { throw new IllegalArgumentException("Edge already exists"); } _edges.put(new Pair(v1,v2),w); _inbounds.get(v2).add(v1); _outbounds.get(v1).add(v2); } public void removeEdge(Integer v1, Integer v2) { if(!_vertices.contains(v1) || !_vertices.contains(v2)) { throw new IllegalArgumentException("Vertex does not exist"); } if(!_edges.containsKey(new Pair(v1,v2))) { throw new IllegalArgumentException("Edge does not exist"); } _edges.remove(new Pair(v1,v2)); _inbounds.get(v2).remove(v1); _outbounds.get(v1).remove(v2); } public HashMap> shortestPath(Integer v){ //Initializations Queue queue = new LinkedList(); HashMap> map = new HashMap>(); Set visited = new HashSet(); for(Iterator vertex = this._vertices.iterator();vertex.hasNext();){ map.put(vertex.next(),new Pair(null,-1)); } //Add the first vertex to the queue, the visited set, and the map of distances and parents with a distance of 0 map.put(v,new Pair(null,0)); queue.add(v); map.put(v,new Pair(null,0)); visited.add(v); //BFS to find the shortest path while(!queue.isEmpty()){ Integer current = queue.poll(); //Get the next vertex //For each neighbor of the current vertex for(Integer neighbor : _outbounds.get(current)){ //If the neighbor has not been visited, add it to the queue, the visited set, and the map of distances and parents with a distance of 1 more than the current vertex if(!visited.contains(neighbor)){ queue.add(neighbor); visited.add(neighbor); map.put(neighbor,new Pair(current,map.get(current).second+1)); } } } return map; } public HashMap> shortestPath(Integer v,Integer u){ //Initializations Queue queue = new LinkedList(); HashMap> map = new HashMap>(); Set visited = new HashSet(); for(Iterator vertex = this._vertices.iterator();vertex.hasNext();){ map.put(vertex.next(),new Pair(null,-1)); } //Add the first vertex to the queue, the visited set, and the map of distances and parents with a distance of 0 map.put(v,new Pair(null,0)); queue.add(v); map.put(v,new Pair(null,0)); visited.add(v); //BFS to find the shortest path while(!queue.isEmpty()){ Integer current = queue.poll(); //Get the next vertex //For each neighbor of the current vertex for(Integer neighbor : _outbounds.get(current)){ //If the neighbor has not been visited yet add it to the queue, visited set, and map. if(!visited.contains(neighbor)){ queue.add(neighbor); visited.add(neighbor); //Add the neighbor to the map with the current vertex as its parent and a distance of the current vertex's distance + 1 map.put(neighbor,new Pair(current,map.get(current).second+1)); //If the neighbor is the destination vertex return the map if(neighbor == u) return map; } } } return map; } public ArrayList path(Integer v1,Integer v2){ //Get the shortest path from v1 to v2 HashMap> map = shortestPath(v1); ArrayList path = new ArrayList(); //If there is no path return an empty arraylist if(map.get(v2).second == -1) return path; path.add(v2); //Add each vertex in the path to the arraylist starting from the destination vertex while(map.containsKey(v2)){ path.add(map.get(v2).first); v2 = map.get(v2).first; } //Remove the first element of the arraylist which is null and reverse the arraylist path.remove(path.size()-1); Collections.reverse(path); return path; } public HashMap,Pair> shortestCost(){ HashMap,Pair> cost_prev_map = new HashMap,Pair>(); for(Integer i : _vertices){ for(Integer j : _vertices){ if(i==j){ cost_prev_map.put(new Pair(i,j),new Pair(0,null)); } else if(_edges.containsKey(new Pair(i,j))){ cost_prev_map.put(new Pair(i,j),new Pair(_edges.get(new Pair(i,j)),i)); } else{ cost_prev_map.put(new Pair(i,j),new Pair(10000,null)); } } } for(Integer k : _vertices){ for(Integer i : _vertices){ for(Integer j : _vertices){ if(cost_prev_map.get(new Pair(i,j)).first > cost_prev_map.get(new Pair(i,k)).first + cost_prev_map.get(new Pair(k,j)).first){ cost_prev_map.put(new Pair(i,j),new Pair(cost_prev_map.get(new Pair(i,k)).first + cost_prev_map.get(new Pair(k,j)).first,cost_prev_map.get(new Pair(k,j)).second)); } } } } //Check for negative cycles for(Integer i : _vertices){ if(cost_prev_map.get(new Pair(i,i)).first < 0){ throw new IllegalArgumentException("Graph contains negative cycle"); } } return cost_prev_map; } public ArrayList costPath(Integer v1,Integer v2){ HashMap,Pair> cost_prev_map = shortestCost(); ArrayList path = new ArrayList(); if(cost_prev_map.get(new Pair(v1,v2)).first == 10000){ return path; } path.add(v2); while(cost_prev_map.get(new Pair(v1,v2)).second != null){ path.add(cost_prev_map.get(new Pair(v1,v2)).second); v2 = cost_prev_map.get(new Pair(v1,v2)).second; } Collections.reverse(path); return path; } public HashMap,Pair> shortestCostDynamic(Integer v1, Integer v2){ HashMap,Pair> cost_prev_map = new HashMap,Pair>(); //Initialize the map with the first vertex having a distance of 0 and all other vertices having a distance of 10000 for(Integer i : _vertices){ if(i==v1){ cost_prev_map.put(new Pair(i,0),new Pair(0,null)); } else{ cost_prev_map.put(new Pair(i,0),new Pair(10000,null)); } } //For each iteration of k for(Integer k = 1; k < _vertices.size(); k++){ for(Integer i : _vertices){ for(Integer j : _vertices){ //If the vertex is an edge and the cost of the previous vertex is greater than the current vertex's cost if(this.isEdge(j,i) && cost_prev_map.get(new Pair(i,k-1)).first > cost_prev_map.get(new Pair(j,k-1)).first + this.weight(j,i)){ //Set the cost of the current vertex to the cost of the previous vertex cost_prev_map.put(new Pair(i,k),new Pair(cost_prev_map.get(new Pair(j,k-1)).first + this.weight(j,i),j)); } } //If the vertex is not an edge and the cost of the previous vertex is greater than the current vertex's cost if(!cost_prev_map.containsKey(new Pair(i,k))){ //Set the cost of the current vertex to the cost of the previous vertex cost_prev_map.put(new Pair(i,k),new Pair(cost_prev_map.get(new Pair(i,k-1)).first,cost_prev_map.get(new Pair(i,k-1)).second)); } } } //Check for negative cycles if(cost_prev_map.get(new Pair(v1,v1)).first < 0){ throw new IllegalArgumentException("Graph contains negative cycle"); } return cost_prev_map; } public ArrayList costPathDynamic(Integer v1,Integer v2){ HashMap,Pair> cost_prev_map = shortestCostDynamic(v1,v2); ArrayList path = new ArrayList(); //If the cost of the last vertex is 10000(infinity), then there is no path if(cost_prev_map.get(new Pair(v2,_vertices.size()-1)).first == 10000){ return path; } //Add the last vertex to the path path.add(v2); Integer k = _vertices.size()-1; //While the previous vertex is not null (the first vertex), add the previous vertex to the path, and set the current vertex to the previous vertex, and decrement k while(cost_prev_map.get(new Pair(v2,k)).second != null){ path.add(cost_prev_map.get(new Pair(v2,k)).second); v2 = cost_prev_map.get(new Pair(v2,k)).second; k--; } Collections.reverse(path); return path; } }