“The shortest-path algorithms are all single-source algorithms, which begin at some starting point and compute the shortest paths from it to all vertices.” Weiss ALG0183 Algorithms & Data Structures Lecture 19 The basics of Graph.java (code by Weiss) Weiss, Chapter 14 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 1 What does Graph.java do? • The user specifies a graph in a text file. • Graph.java reads the text file and builds up an internal representation of the graph. • The user enters start and destination nodes. • The user specifies which algorithm should be executed to find the shortest path: – – – – u unweighted (breadth-first search algorithm) d only positive weights on edges (Dijkstra´s algorithm) n negative weights present (Bellman-Ford algorithm) a acyclic with neg. weights (topological sort algorithm) • Graph.java reports the shortest path (or an exception in the event of an error). 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 2 sample input file “graph1.txt” Figure 14.5 Weiss ©Addison Wesley The input is a list of edges, one per line. Graph.java does not know the names of the vertices, nor how many vertices and edges there are: it reads the input file to find out. 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 3 sample I/O for graph1.txt File read... 5 vertices Enter start node:A Enter destination node:D Enter algorithm (u, d, n, a ): u unweighted (Cost is: 1.0) A to D Enter start node:A Enter destination node:D Enter algorithm (u, d, n, a ): d Dijkstra (positive) (Cost is: 66.0) A to B to E to D (Cost is: 66.0) A to B to E to D Enter start node:A Enter destination node:D Enter algorithm (u, d, n, a ): n Bellman-Ford (with negative) (Cost is: 66.0) A to B to E to D Enter start node:A Enter destination node:D Enter algorithm (u, d, n, a ): a acyclic (topological sort) Enter start node:gr.GraphException: Graph has a cycle! 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 4 try { System.out.print( "Enter start node:" ); if( ( startName = in.readLine( ) ) == null ) return false; System.out.print( "Enter destination node:" ); if( ( destName = in.readLine( ) ) == null ) return false; System.out.print( " Enter algorithm (u, d, n, a ): " ); if( ( alg = in.readLine( ) ) == null ) return false; if( alg.equals( "u" ) ) u unweighted g.unweighted( startName ); else if( alg.equals( "d" ) ) { d Dijkstra (positive) g.dijkstra( startName ); g.printPath( destName ); // g.dijkstra2( startName ); } else if( alg.equals( "n" ) ) n Bellman-Ford (with negative) g.negative( startName ); else if( alg.equals( "a" ) ) a acyclic (topological sort) g.acyclic( startName ); g.printPath( destName ); } 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 5 Graph g = new Graph( ); try { FileReader fin = new FileReader(args[0]); BufferedReader graphFile = new BufferedReader( fin ); // Read the edges and insert String line; while( ( line = graphFile.readLine( ) ) != null ) { StringTokenizer st = new StringTokenizer( line ); try { if( st.countTokens( ) != 3 ) { System.err.println( "Skipping ill-formatted line " + line ); continue; } String source = st.nextToken( ); String dest = st.nextToken( ); int cost = Integer.parseInt( st.nextToken( ) ); g.addEdge( source, dest, cost ); } 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 6 Some imports in Graph.java import java.io.FileReader; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; import java.util.StringTokenizer; //import java.util.Iterator; import java.util.Collection; import java.util.List; import java.util.Queue; import java.util.Map; import java.util.LinkedList; import java.util.HashMap; import java.util.NoSuchElementException; import java.util.PriorityQueue; 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 7 The beginning of the Graph class public class Graph { public static final double INFINITY = Double.MAX_VALUE; private Map<String,Vertex> vertexMap = new HashMap<String,Vertex>( ); • According to the Java API, Double.MAX_VALUE is “A constant holding the largest positive finite value of type double, (2-2-52)·21023.” – i.e. 1.7976931348623157E308 • The cost of reaching a vertex is initially set to INFINITY. else if( w.dist == INFINITY ) System.out.println( destName + " is unreachable" ); See later: code in method printPath. 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 8 key value What is a HashMap? • • • • • • HashMap implements the Map interface. An entry in a map has a key and a value. Duplicate keys are not allowed. A key can be an instance of any class. A value can be an instance of any class. To retrieve a value associated with a key, the map´s get method is called. – The key is the index into a map collection. • There is no guarantee of the order of entries in a HashMap. • The type for the key and value must be specified when declaring and creating a map. private Map<String,Vertex> vertexMap = new HashMap<String,Vertex>( ); 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 9 Hash table @ Wikipedia 27.10.2009 “In computer science, a hash table or hash map is a data structure that uses a hash function to efficiently map certain identifiers or keys (e.g., person names) to associated values (e.g., their telephone numbers). The hash function is used to transform the key into the index (the hash) of an array element (the slot or bucket) where the corresponding value is to be sought.” 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 10 HashMap @ Java API http://java.sun.com/javase/6/docs/api/ • “This implementation provides constant-time performance for the basic operations (get and put), assuming the hash function disperses the elements properly among the buckets.” • “The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.” 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 11 // Represents a vertex in the graph. class Vertex { public String name; // Vertex name the vertex name never changes public List<Edge> adj; // Adjacent vertices the list of edges never changes public double dist; // Cost from the starting vertex to this vertex public Vertex prev; // Previous vertex on shortest path public int scratch;// Extra variable used in algorithm public Vertex( String nm ) the constructor { name = nm; adj = new LinkedList<Edge>( ); reset( ); } public void reset( ) initialization { dist = Graph.INFINITY; prev = null; scratch = 0; } //{ dist = Graph.INFINITY; prev = null; pos = null; scratch = 0; } // public PairingHeap.Position<Path> pos; // Used for dijkstra2 (Chapter 23) } 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 12 cost destination // Represents an edge in the graph. class Edge { public Vertex dest; // Second vertex in Edge public double cost; // Edge cost public Edge( Vertex d, double c ) { dest = d; cost = c; } the destination weight the constructor } Edges are stored in an adjacency list. 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 13 /** * Add a new edge to the graph. */ public void addEdge( String sourceName, String destName, double cost ) { Vertex v = getVertex( sourceName ); Vertex w = getVertex( destName ); v.adj.add( new Edge( w, cost ) ); } g.addEdge( source, dest, cost ); See earlier: code in method main. Note that the method getVertex can also create the object if necessary: it is not a simple get method. 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 14 /** * If vertexName is not present, add it to vertexMap. * In either case, return the Vertex. */ private Vertex getVertex( String vertexName ) { Vertex v = vertexMap.get( vertexName ); get the vertex from the map if( v == null ) but if the vertex does not exist { v = new Vertex( vertexName ); create a new vertex and… vertexMap.put( vertexName, v ); …put it in the map } return v; } “The getVertex routine returns the Vertex objetc that represents vertexName, creating the object if it needs to do.” Weiss 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 15 /** * Initializes the vertex output info prior to running * any shortest path algorithm. */ private void clearAll( ) { for( Vertex v : vertexMap.values( ) ) values() returns a “Collection view” v.reset( ); } public void reset( ) { dist = Graph.INFINITY; prev = null; scratch = 0; } See earlier: code in class Vertex. 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 16 /** * Driver routine to handle unreachables and print total cost. * It calls recursive routine to print shortest path to * destNode after a shortest path algorithm has run. */ public void printPath( String destName ) { Vertex w = vertexMap.get( destName ); if( w == null ) throw new NoSuchElementException( "Destination vertex not found" ); else if( w.dist == INFINITY ) System.out.println( destName + " is unreachable" ); else { System.out.print( "(Cost is: " + w.dist + ") " ); printPath( w ); note that the argument references a vertex System.out.println( ); } } ALG0183 Algorithms & Data Structures by 8/25/2009 17 Dr Andy Brooks different signature /** * Recursive routine to print shortest path to dest * after running shortest path algorithm. The path * is known to exist. */ private void printPath( Vertex dest ) the argument references a vertex { if( dest.prev != null ) { printPath( dest.prev ); System.out.print( " to " ); } System.out.print( dest.name ); } 8/25/2009 ALG0183 Algorithms & Data Structures by Dr Andy Brooks 18