//Initializes an empty graph with V vertices and 0 edges. publicGraph(int V) { if (V < 0) thrownew IllegalArgumentException("Number of vertices must be nonnegative"); this.V = V; this.E = 0; adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Integer>(); }
//Initializes a graph from the specified input stream. publicGraph(In in) { if (in == null) thrownew IllegalArgumentException("argument is null"); try { this.V = in.readInt(); if (V < 0) thrownew IllegalArgumentException("number of vertices in a Graph must be nonnegative"); adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Integer>(); int E = in.readInt(); if (E < 0) thrownew IllegalArgumentException("number of edges in a Graph must be nonnegative"); for (int i = 0; i < E; i++) { int v = in.readInt(); int w = in.readInt(); validateVertex(v); validateVertex(w); addEdge(v, w); } } catch (NoSuchElementException e) { thrownew IllegalArgumentException("invalid input format in Graph constructor", e); } }
//Initializes a new graph that is a deep copy of G. publicGraph(Graph G) { this.V = G.V(); this.E = G.E(); if (V < 0) thrownew IllegalArgumentException("Number of vertices must be nonnegative");
// update adjacency lists adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Integer>();
for (int v = 0; v < G.V(); v++) { // reverse so that adjacency list is in same order as original Stack<Integer> reverse = new Stack<Integer>(); for (int w : G.adj[v]) reverse.push(w); for (int w : reverse) adj[v].add(w); } }
//Returns the number of vertices in this graph. publicintV() { return V; }
//Returns the number of edges in this graph. publicintE() { return E; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
//Adds the undirected edge v-w to this graph. publicvoidaddEdge(int v, int w) { validateVertex(v); validateVertex(w); E++; adj[v].add(w); adj[w].add(v); }
//Returns the vertices adjacent to vertex {@code v}. public Iterable<Integer> adj(int v) { validateVertex(v); return adj[v]; }
//Returns the degree of vertex {@code v}. publicintdegree(int v) { validateVertex(v); return adj[v].size(); }
//Returns a string representation of this graph. public String toString() { StringBuilder s = new StringBuilder(); s.append(V + " vertices, " + E + " edges " + NEWLINE); for (int v = 0; v < V; v++) { s.append(v + ": "); for (int w : adj[v]) { s.append(w + " "); } s.append(NEWLINE); } return s.toString(); }
/** * Unit tests the {@code Graph} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Graph G = new Graph(in); StdOut.println(G); }
publicclassDepthFirstSearch { privateboolean[] marked; // marked[v] = is there an s-v path? privateint count; // number of vertices connected to s
/** * Computes the vertices in graph {@code G} that are * connected to the source vertex {@code s}. */ publicDepthFirstSearch(Graph G, int s) { marked = newboolean[G.V()]; validateVertex(s); dfs(G, s); }
// depth first search from v privatevoiddfs(Graph G, int v) { count++; marked[v] = true; for (int w : G.adj(v)) { if (!marked[w]) { dfs(G, w); } } } //Is there a path between the source vertex {@code s} and vertex {@code v}? publicbooleanmarked(int v) { validateVertex(v); return marked[v]; } //Returns the number of vertices connected to the source vertex {@code s}. publicintcount() { return count; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V - 1)); }
/** * Unit tests the {@code DepthFirstSearch} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Graph G = new Graph(in); int s = Integer.parseInt(args[1]); DepthFirstSearch search = new DepthFirstSearch(G, s); for (int v = 0; v < G.V(); v++) { if (search.marked(v)) StdOut.print(v + " "); }
publicclassDepthFirstPaths{ privateboolean[] marked; // marked[v] = is there an s-v path? privateint[] edgeTo; // edgeTo[v] = last edge on s-v path privatefinalint s; // source vertex
//Computes a path between {@code s} and every other vertex in graph {@code G}. publicDepthFirstPaths(Graph G, int s) { this.s = s; edgeTo = newint[G.V()]; marked = newboolean[G.V()]; validateVertex(s); dfs(G, s); }
// depth first search from v privatevoiddfs(Graph G, int v) { marked[v] = true; for (int w : G.adj(v)) { if (!marked[w]) { edgeTo[w] = v; dfs(G, w); } } }
//Is there a path between the source vertex {@code s} and vertex {@code v}? publicbooleanhasPathTo(int v) { validateVertex(v); return marked[v]; }
//Returns a path between the source vertex {@code s} and vertex {@code v}, or public Iterable<Integer> pathTo(int v) { validateVertex(v); if (!hasPathTo(v)) returnnull; Stack<Integer> path = new Stack<Integer>(); for (int x = v; x != s; x = edgeTo[x]) path.push(x); path.push(s); return path; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code DepthFirstPaths} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Graph G = new Graph(in); int s = Integer.parseInt(args[1]); DepthFirstPaths dfs = new DepthFirstPaths(G, s);
for (int v = 0; v < G.V(); v++) { if (dfs.hasPathTo(v)) { StdOut.printf("%d to %d: ", s, v); for (int x : dfs.pathTo(v)) { if (x == s) StdOut.print(x); else StdOut.print("-" + x); } StdOut.println(); } else { StdOut.printf("%d to %d: not connected\n", s, v); }
} } }
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
%more tinyCG.txt 6 8 05 24 23 12 01 34 35 02
%java DepthFirstPaths tinyCG.txt 0 0 to 0: 0 0 to 1: 0-2-1 0 to 2: 0-2 0 to 3: 0-2-3 0 to 4: 0-2-3-4 0 to 5: 0-2-3-5
publicclassBreadthFirstPaths { privatestaticfinalint INFINITY = Integer.MAX_VALUE; privateboolean[] marked; // marked[v] = is there an s-v path privateint[] edgeTo; // edgeTo[v] = previous edge on shortest s-v path privateint[] distTo; // distTo[v] = number of edges shortest s-v path
//Computes the shortest path between the source vertex {@code s} publicBreadthFirstPaths(Graph G, int s) { marked = newboolean[G.V()]; distTo = newint[G.V()]; edgeTo = newint[G.V()]; validateVertex(s); bfs(G, s);
assertcheck(G, s); }
//Computes the shortest path between any one of the source vertices in {@code sources} publicBreadthFirstPaths(Graph G, Iterable<Integer> sources) { marked = newboolean[G.V()]; distTo = newint[G.V()]; edgeTo = newint[G.V()]; for (int v = 0; v < G.V(); v++) distTo[v] = INFINITY; validateVertices(sources); bfs(G, sources); }
// breadth-first search from a single source privatevoidbfs(Graph G, int s) { Queue<Integer> q = new Queue<Integer>(); for (int v = 0; v < G.V(); v++) distTo[v] = INFINITY; distTo[s] = 0; marked[s] = true; q.enqueue(s);
while (!q.isEmpty()) { int v = q.dequeue(); for (int w : G.adj(v)) { if (!marked[w]) { edgeTo[w] = v; distTo[w] = distTo[v] + 1; marked[w] = true; q.enqueue(w); } } } }
// breadth-first search from multiple sources privatevoidbfs(Graph G, Iterable<Integer> sources) { Queue<Integer> q = new Queue<Integer>(); for (int s : sources) { marked[s] = true; distTo[s] = 0; q.enqueue(s); } while (!q.isEmpty()) { int v = q.dequeue(); for (int w : G.adj(v)) { if (!marked[w]) { edgeTo[w] = v; distTo[w] = distTo[v] + 1; marked[w] = true; q.enqueue(w); } } } }
//Is there a path between the source vertex {@code s} (or sources) and vertex {@code v}? publicbooleanhasPathTo(int v) { validateVertex(v); return marked[v]; }
//Returns the number of edges in a shortest path between the source vertex {@code s} publicintdistTo(int v) { validateVertex(v); return distTo[v]; }
//Returns a shortest path between the source vertex {@code s} (or sources) public Iterable<Integer> pathTo(int v) { validateVertex(v); if (!hasPathTo(v)) returnnull; Stack<Integer> path = new Stack<Integer>(); int x; for (x = v; distTo[x] != 0; x = edgeTo[x]) path.push(x); path.push(x); return path; }
// check optimality conditions for single source privatebooleancheck(Graph G, int s) {
// check that the distance of s = 0 if (distTo[s] != 0) { StdOut.println("distance of source " + s + " to itself = " + distTo[s]); returnfalse; }
// check that for each edge v-w dist[w] <= dist[v] + 1 // provided v is reachable from s for (int v = 0; v < G.V(); v++) { for (int w : G.adj(v)) { if (hasPathTo(v) != hasPathTo(w)) { StdOut.println("edge " + v + "-" + w); StdOut.println("hasPathTo(" + v + ") = " + hasPathTo(v)); StdOut.println("hasPathTo(" + w + ") = " + hasPathTo(w)); returnfalse; } if (hasPathTo(v) && (distTo[w] > distTo[v] + 1)) { StdOut.println("edge " + v + "-" + w); StdOut.println("distTo[" + v + "] = " + distTo[v]); StdOut.println("distTo[" + w + "] = " + distTo[w]); returnfalse; } } }
// check that v = edgeTo[w] satisfies distTo[w] = distTo[v] + 1 // provided v is reachable from s for (int w = 0; w < G.V(); w++) { if (!hasPathTo(w) || w == s) continue; int v = edgeTo[w]; if (distTo[w] != distTo[v] + 1) { StdOut.println("shortest path edge " + v + "-" + w); StdOut.println("distTo[" + v + "] = " + distTo[v]); StdOut.println("distTo[" + w + "] = " + distTo[w]); returnfalse; } }
returntrue; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertices(Iterable<Integer> vertices) { if (vertices == null) { thrownew IllegalArgumentException("argument is null"); } for (Integer v : vertices) { if (v == null) { thrownew IllegalArgumentException("vertex is null"); } validateVertex(v); } }
/** * Unit tests the {@code BreadthFirstPaths} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Graph G = new Graph(in); // StdOut.println(G);
int s = Integer.parseInt(args[1]); BreadthFirstPaths bfs = new BreadthFirstPaths(G, s);
for (int v = 0; v < G.V(); v++) { if (bfs.hasPathTo(v)) { StdOut.printf("%d to %d (%d): ", s, v, bfs.distTo(v)); for (int x : bfs.pathTo(v)) { if (x == s) StdOut.print(x); else StdOut.print("-" + x); } StdOut.println(); }
else { StdOut.printf("%d to %d (-): not connected\n", s, v); }
} } }
测试
1 2 3 4 5 6 7
%java BreadthFirstPaths tinyCG.txt 0 0 to 0: 0 0 to 1: 0-1 0 to 2: 0-2 0 to 3: 0-2-3 0 to 4: 0-2-4 0 to 5: 0-5
publicclassCC { privateboolean[] marked; // marked[v] = has vertex v been marked? privateint[] id; // id[v] = id of connected component containing v privateint[] size; // size[id] = number of vertices in given component privateint count; // number of connected components //Computes the connected components of the undirected graph {@code G}. publicCC(Graph G) { marked = newboolean[G.V()]; id = newint[G.V()]; size = newint[G.V()]; for (int v = 0; v < G.V(); v++) { if (!marked[v]) { dfs(G, v); count++; } } } //Computes the connected components of the edge-weighted graph {@code G}. publicCC(EdgeWeightedGraph G) { marked = newboolean[G.V()]; id = newint[G.V()]; size = newint[G.V()]; for (int v = 0; v < G.V(); v++) { if (!marked[v]) { dfs(G, v); count++; } } }
// depth-first search for a Graph privatevoiddfs(Graph G, int v) { marked[v] = true; id[v] = count; size[count]++; for (int w : G.adj(v)) { if (!marked[w]) { dfs(G, w); } } }
// depth-first search for an EdgeWeightedGraph privatevoiddfs(EdgeWeightedGraph G, int v) { marked[v] = true; id[v] = count; size[count]++; for (Edge e : G.adj(v)) { int w = e.other(v); if (!marked[w]) { dfs(G, w); } } }
//Returns the component id of the connected component containing vertex {@code v}. publicintid(int v) { validateVertex(v); return id[v]; } //Returns the number of vertices in the connected component containing vertex {@code v}. publicintsize(int v) { validateVertex(v); return size[id[v]]; } //Returns the number of connected components in the graph {@code G}. publicintcount() { return count; } //Returns true if vertices {@code v} and {@code w} are in the same publicbooleanconnected(int v, int w) { validateVertex(v); validateVertex(w); return id(v) == id(w); }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code CC} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Graph G = new Graph(in); CC cc = new CC(G);
// number of connected components int m = cc.count(); StdOut.println(m + " components");
// compute list of vertices in each connected component Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m]; for (int i = 0; i < m; i++) { components[i] = new Queue<Integer>(); } for (int v = 0; v < G.V(); v++) { components[cc.id(v)].enqueue(v); }
// print results for (int i = 0; i < m; i++) { for (int v : components[i]) { StdOut.print(v + " "); } StdOut.println(); } } }
publicclassSymbolGraph { private ST<String, Integer> st; // string -> index private String[] keys; // index -> string private Graph graph; // the underlying graph //Initializes a graph from a file using the specified delimiter. publicSymbolGraph(String filename, String delimiter) { st = new ST<String, Integer>();
// First pass builds the index by reading strings to associate // distinct strings with an index In in = new In(filename); while (!in.isEmpty()) { String[] a = in.readLine().split(delimiter); for (int i = 0; i < a.length; i++) { if (!st.contains(a[i])) st.put(a[i], st.size()); } }
// inverted index to get string keys in an array keys = new String[st.size()]; for (String name : st.keys()) keys[st.get(name)] = name;
// second pass builds the graph by connecting first vertex on each // line to all others graph = new Graph(st.size()); in = new In(filename); while (in.hasNextLine()) { String[] a = in.readLine().split(delimiter); int v = st.get(a[0]); for (int i = 1; i < a.length; i++) { int w = st.get(a[i]); graph.addEdge(v, w); } } } //Does the graph contain the vertex named {@code s}? publicbooleancontains(String s) { return st.contains(s); }
//Returns the integer associated with the vertex named {@code s}. publicintindexOf(String s) { return st.get(s); }
//Returns the name of the vertex associated with the integer {@code v}. public String nameOf(int v) { validateVertex(v); return keys[v]; }
//Returns the graph assoicated with the symbol graph. It is the client's responsibility public Graph graph() { return graph; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = graph.V(); if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V - 1)); }
/** * Unit tests the {@code SymbolGraph} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { String filename = args[0]; String delimiter = args[1]; SymbolGraph sg = new SymbolGraph(filename, delimiter); Graph graph = sg.graph(); while (StdIn.hasNextLine()) { String source = StdIn.readLine(); if (sg.contains(source)) { int s = sg.indexOf(source); for (int v : graph.adj(s)) { StdOut.println(" " + sg.nameOf(v)); } } else { StdOut.println("input not contain '" + source + "'"); } } } }
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
% java SymbolGraph movies.txt "/" Tin Men (1987) Hershey, Barbara Geppi, Cindy Jones, Kathy (II) Herr, Marcia ... Blumenfeld, Alan DeBoy, David Bacon, Kevin Woodsman, The (2004) Wild Things (1998) Where the Truth Lies (2005) Tremors (1990) ... Apollo 13 (1995) Animal House (1978)
privatefinalint V; // number of vertices in this digraph privateint E; // number of edges in this digraph private Bag<Integer>[] adj; // adj[v] = adjacency list for vertex v privateint[] indegree; // indegree[v] = indegree of vertex v
//Initializes an empty digraph with V vertices. publicDigraph(int V) { if (V < 0) thrownew IllegalArgumentException("Number of vertices in a Digraph must be nonnegative"); this.V = V; this.E = 0; indegree = newint[V]; adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Integer>(); }
//Initializes a digraph from the specified input stream. publicDigraph(In in) { if (in == null) thrownew IllegalArgumentException("argument is null"); try { this.V = in.readInt(); if (V < 0) thrownew IllegalArgumentException("number of vertices in a Digraph must be nonnegative"); indegree = newint[V]; adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Integer>(); int E = in.readInt(); if (E < 0) thrownew IllegalArgumentException("number of edges in a Digraph must be nonnegative"); for (int i = 0; i < E; i++) { int v = in.readInt(); int w = in.readInt(); addEdge(v, w); } } catch (NoSuchElementException e) { thrownew IllegalArgumentException("invalid input format in Digraph constructor", e); } }
//Initializes a new digraph that is a deep copy of the specified digraph. publicDigraph(Digraph G) { if (G == null) thrownew IllegalArgumentException("argument is null");
this.V = G.V(); this.E = G.E(); if (V < 0) thrownew IllegalArgumentException("Number of vertices in a Digraph must be nonnegative");
// update indegrees indegree = newint[V]; for (int v = 0; v < V; v++) this.indegree[v] = G.indegree(v);
// update adjacency lists adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Integer>();
for (int v = 0; v < G.V(); v++) { // reverse so that adjacency list is in same order as original Stack<Integer> reverse = new Stack<Integer>(); for (int w : G.adj[v]) reverse.push(w); for (int w : reverse) adj[v].add(w); } }
//Returns the number of vertices in this digraph. publicintV() { return V; }
//Returns the number of edges in this digraph. publicintE() { return E; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
//Adds the directed edge v→w to this digraph. publicvoidaddEdge(int v, int w) { validateVertex(v); validateVertex(w); adj[v].add(w); indegree[w]++; E++; }
//Returns the vertices adjacent from vertex {@code v} in this digraph. public Iterable<Integer> adj(int v) { validateVertex(v); return adj[v]; }
//Returns the number of directed edges incident from vertex {@code v}. publicintoutdegree(int v) { validateVertex(v); return adj[v].size(); }
//Returns the number of directed edges incident to vertex {@code v}. publicintindegree(int v) { validateVertex(v); return indegree[v]; }
//Returns the reverse of the digraph. public Digraph reverse() { Digraph reverse = new Digraph(V); for (int v = 0; v < V; v++) { for (int w : adj(v)) reverse.addEdge(w, v); } return reverse; }
//Returns a string representation of the graph. public String toString() { StringBuilder s = new StringBuilder(); s.append(V + " vertices, " + E + " edges " + NEWLINE); for (int v = 0; v < V; v++) { s.append(String.format("%d: ", v)); for (int w : adj[v]) s.append(String.format("%d ", w)); s.append(NEWLINE); } return s.toString(); } }
publicclassDirectedCycle { privateboolean[] marked; // marked[v] = has vertex v been marked? privateint[] edgeTo; // edgeTo[v] = previous vertex on path to v privateboolean[] onStack; // onStack[v] = is vertex on the stack? private Stack<Integer> cycle; // directed cycle (or null if no such cycle)
//Determines whether the digraph {@code G} has a directed cycle and, if so, publicDirectedCycle(Digraph G) { marked = newboolean[G.V()]; onStack = newboolean[G.V()]; edgeTo = newint[G.V()]; for (int v = 0; v < G.V(); v++) if (!marked[v] && cycle == null) dfs(G, v); }
// run DFS and find a directed cycle (if one exists) privatevoiddfs(Digraph G, int v) { onStack[v] = true; marked[v] = true; for (int w : G.adj(v)) {
// short circuit if directed cycle found if (cycle != null) return;
// found new vertex, so recur elseif (!marked[w]) { edgeTo[w] = v; dfs(G, w); }
// trace back directed cycle elseif (onStack[w]) { cycle = new Stack<Integer>(); for (int x = v; x != w; x = edgeTo[x]) { cycle.push(x); } cycle.push(w); cycle.push(v); assertcheck(); } } onStack[v] = false; }
//Does the digraph have a directed cycle? publicbooleanhasCycle() { return cycle != null; }
//Returns a directed cycle if the digraph has a directed cycle, and {@code null} otherwise. public Iterable<Integer> cycle() { return cycle; }
// certify that digraph has a directed cycle if it reports one privatebooleancheck() {
if (hasCycle()) { // verify cycle int first = -1, last = -1; for (int v : cycle()) { if (first == -1) first = v; last = v; } if (first != last) { System.err.printf("cycle begins with %d and ends with %d\n", first, last); returnfalse; } }
returntrue; }
/** * Unit tests the {@code DirectedCycle} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Digraph G = new Digraph(in);
DirectedCycle finder = new DirectedCycle(G); if (finder.hasCycle()) { StdOut.print("Directed cycle: "); for (int v : finder.cycle()) { StdOut.print(v + " "); } StdOut.println(); }
publicclassEdgeWeightedDirectedCycle { privateboolean[] marked; // marked[v] = has vertex v been marked? private DirectedEdge[] edgeTo; // edgeTo[v] = previous edge on path to v privateboolean[] onStack; // onStack[v] = is vertex on the stack? private Stack<DirectedEdge> cycle; // directed cycle (or null if no such cycle)
/** * Determines whether the edge-weighted digraph {@code G} has a directed cycle and, * if so, finds such a cycle. */ publicEdgeWeightedDirectedCycle(EdgeWeightedDigraph G) { marked = newboolean[G.V()]; onStack = newboolean[G.V()]; edgeTo = new DirectedEdge[G.V()]; for (int v = 0; v < G.V(); v++) if (!marked[v]) dfs(G, v);
// check that digraph has a cycle assertcheck(); }
// check that algorithm computes either the topological order or finds a directed cycle privatevoiddfs(EdgeWeightedDigraph G, int v) { onStack[v] = true; marked[v] = true; for (DirectedEdge e : G.adj(v)) { int w = e.to();
// short circuit if directed cycle found if (cycle != null) return;
// found new vertex, so recur elseif (!marked[w]) { edgeTo[w] = e; dfs(G, w); }
// trace back directed cycle elseif (onStack[w]) { cycle = new Stack<DirectedEdge>();
DirectedEdge f = e; while (f.from() != w) { cycle.push(f); f = edgeTo[f.from()]; } cycle.push(f);
return; } }
onStack[v] = false; }
//Does the edge-weighted digraph have a directed cycle? publicbooleanhasCycle() { return cycle != null; }
/** * Returns a directed cycle if the edge-weighted digraph has a directed cycle, * and {@code null} otherwise. */ public Iterable<DirectedEdge> cycle() { return cycle; }
// certify that digraph is either acyclic or has a directed cycle privatebooleancheck() {
// edge-weighted digraph is cyclic if (hasCycle()) { // verify cycle DirectedEdge first = null, last = null; for (DirectedEdge e : cycle()) { if (first == null) first = e; if (last != null) { if (last.to() != e.from()) { System.err.printf("cycle edges %s and %s not incident\n", last, e); returnfalse; } } last = e; }
if (last.to() != first.from()) { System.err.printf("cycle edges %s and %s not incident\n", last, first); returnfalse; } }
returntrue; }
/** * Unit tests the {@code EdgeWeightedDirectedCycle} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) {
// create random DAG with V vertices and E edges; then add F random edges int V = Integer.parseInt(args[0]); int E = Integer.parseInt(args[1]); int F = Integer.parseInt(args[2]); EdgeWeightedDigraph G = new EdgeWeightedDigraph(V); int[] vertices = newint[V]; for (int i = 0; i < V; i++) vertices[i] = i; StdRandom.shuffle(vertices); for (int i = 0; i < E; i++) { int v, w; do { v = StdRandom.uniform(V); w = StdRandom.uniform(V); } while (v >= w); double weight = StdRandom.uniform(); G.addEdge(new DirectedEdge(v, w, weight)); }
// add F extra edges for (int i = 0; i < F; i++) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); double weight = StdRandom.uniform(0.0, 1.0); G.addEdge(new DirectedEdge(v, w, weight)); }
StdOut.println(G);
// find a directed cycle EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(G); if (finder.hasCycle()) { StdOut.print("Cycle: "); for (DirectedEdge e : finder.cycle()) { StdOut.print(e + " "); } StdOut.println(); }
// or give topologial sort else { StdOut.println("No directed cycle"); } }
publicclassDepthFirstOrder { privateboolean[] marked; // marked[v] = has v been marked in dfs? privateint[] pre; // pre[v] = preorder number of v privateint[] post; // post[v] = postorder number of v private Queue<Integer> preorder; // vertices in preorder private Queue<Integer> postorder; // vertices in postorder privateint preCounter; // counter or preorder numbering privateint postCounter; // counter for postorder numbering
publicDepthFirstOrder(Digraph G) { pre = newint[G.V()]; post = newint[G.V()]; postorder = new Queue<Integer>(); preorder = new Queue<Integer>(); marked = newboolean[G.V()]; for (int v = 0; v < G.V(); v++) if (!marked[v]) dfs(G, v);
assertcheck(); }
//Determines a depth-first order for the edge-weighted digraph {@code G}. publicDepthFirstOrder(EdgeWeightedDigraph G) { pre = newint[G.V()]; post = newint[G.V()]; postorder = new Queue<Integer>(); preorder = new Queue<Integer>(); marked = newboolean[G.V()]; for (int v = 0; v < G.V(); v++) if (!marked[v]) dfs(G, v); }
// run DFS in digraph G from vertex v and compute preorder/postorder privatevoiddfs(Digraph G, int v) { marked[v] = true; pre[v] = preCounter++; preorder.enqueue(v); for (int w : G.adj(v)) { if (!marked[w]) { dfs(G, w); } } postorder.enqueue(v); post[v] = postCounter++; }
// run DFS in edge-weighted digraph G from vertex v and compute preorder/postorder privatevoiddfs(EdgeWeightedDigraph G, int v) { marked[v] = true; pre[v] = preCounter++; preorder.enqueue(v); for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (!marked[w]) { dfs(G, w); } } postorder.enqueue(v); post[v] = postCounter++; }
//Returns the preorder number of vertex {@code v}. publicintpre(int v) { validateVertex(v); return pre[v]; }
//Returns the postorder number of vertex {@code v}. publicintpost(int v) { validateVertex(v); return post[v]; }
//Returns the vertices in postorder. public Iterable<Integer> post() { return postorder; }
//Returns the vertices in preorder. public Iterable<Integer> pre() { return preorder; } //Returns the vertices in reverse postorder. public Iterable<Integer> reversePost() { Stack<Integer> reverse = new Stack<Integer>(); for (int v : postorder) reverse.push(v); return reverse; }
// check that pre() and post() are consistent with pre(v) and post(v) privatebooleancheck() {
// check that post(v) is consistent with post() int r = 0; for (int v : post()) { if (post(v) != r) { StdOut.println("post(v) and post() inconsistent"); returnfalse; } r++; }
// check that pre(v) is consistent with pre() r = 0; for (int v : pre()) { if (pre(v) != r) { StdOut.println("pre(v) and pre() inconsistent"); returnfalse; } r++; }
returntrue; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code DepthFirstOrder} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Digraph G = new Digraph(in);
DepthFirstOrder dfs = new DepthFirstOrder(G); StdOut.println(" v pre post"); StdOut.println("--------------"); for (int v = 0; v < G.V(); v++) StdOut.printf("%4d %4d %4d\n", v, dfs.pre(v), dfs.post(v));
StdOut.print("Preorder: "); for (int v : dfs.pre()) StdOut.print(v + " "); StdOut.println();
StdOut.print("Postorder: "); for (int v : dfs.post()) StdOut.print(v + " "); StdOut.println();
StdOut.print("Reverse postorder: "); for (int v : dfs.reversePost()) StdOut.print(v + " "); StdOut.println(); } }
publicclassTopological { private Iterable<Integer> order; // topological order privateint[] rank; // rank[v] = rank of vertex v in order
/** * Determines whether the digraph {@code G} has a topological order and, if so, * finds such a topological order. */ publicTopological(Digraph G) { DirectedCycle finder = new DirectedCycle(G); if (!finder.hasCycle()) { DepthFirstOrder dfs = new DepthFirstOrder(G); order = dfs.reversePost(); rank = newint[G.V()]; int i = 0; for (int v : order) rank[v] = i++; } }
/** * Determines whether the edge-weighted digraph {@code G} has a topological * order and, if so, finds such an order. */ publicTopological(EdgeWeightedDigraph G) { EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(G); if (!finder.hasCycle()) { DepthFirstOrder dfs = new DepthFirstOrder(G); order = dfs.reversePost(); } }
/** * Returns a topological order if the digraph has a topologial order, * and {@code null} otherwise. */ public Iterable<Integer> order() { return order; }
/** * Does the digraph have a topological order? * @return {@code true} if the digraph has a topological order (or equivalently, * if the digraph is a DAG), and {@code false} otherwise */ publicbooleanhasOrder() { return order != null; }
/** * The the rank of vertex {@code v} in the topological order; * -1 if the digraph is not a DAG */ publicintrank(int v) { validateVertex(v); if (hasOrder()) return rank[v]; elsereturn -1; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = rank.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code Topological} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { String filename = args[0]; String delimiter = args[1]; SymbolDigraph sg = new SymbolDigraph(filename, delimiter); Topological topological = new Topological(sg.digraph()); for (int v : topological.order()) StdOut.println(sg.nameOf(v)); }
publicclassKosarajuSharirSCC { privateboolean[] marked; // marked[v] = has vertex v been visited? privateint[] id; // id[v] = id of strong component containing v privateint count; // number of strongly-connected components
//Computes the strong components of the digraph {@code G}. publicKosarajuSharirSCC(Digraph G) {
// compute reverse postorder of reverse graph DepthFirstOrder dfs = new DepthFirstOrder(G.reverse());
// run DFS on G, using reverse postorder to guide calculation marked = newboolean[G.V()]; id = newint[G.V()]; for (int v : dfs.reversePost()) { if (!marked[v]) { dfs(G, v); count++; } }
// check that id[] gives strong components assertcheck(G); }
// DFS on graph G privatevoiddfs(Digraph G, int v) { marked[v] = true; id[v] = count; for (int w : G.adj(v)) { if (!marked[w]) dfs(G, w); } }
//Returns the number of strong components. publicintcount() { return count; }
//Are vertices {@code v} and {@code w} in the same strong component? publicbooleanstronglyConnected(int v, int w) { validateVertex(v); validateVertex(w); return id[v] == id[w]; }
//Returns the component id of the strong component containing vertex {@code v}. publicintid(int v) { validateVertex(v); return id[v]; }
// does the id[] array contain the strongly connected components? privatebooleancheck(Digraph G) { TransitiveClosure tc = new TransitiveClosure(G); for (int v = 0; v < G.V(); v++) { for (int w = 0; w < G.V(); w++) { if (stronglyConnected(v, w) != (tc.reachable(v, w) && tc.reachable(w, v))) returnfalse; } } returntrue; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code KosarajuSharirSCC} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Digraph G = new Digraph(in); KosarajuSharirSCC scc = new KosarajuSharirSCC(G);
// number of connected components int m = scc.count(); StdOut.println(m + " strong components");
// compute list of vertices in each strong component Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m]; for (int i = 0; i < m; i++) { components[i] = new Queue<Integer>(); } for (int v = 0; v < G.V(); v++) { components[scc.id(v)].enqueue(v); }
// print results for (int i = 0; i < m; i++) { for (int v : components[i]) { StdOut.print(v + " "); } StdOut.println(); }
publicclassTarjanSCC { privateboolean[] marked; // marked[v] = has v been visited? privateint[] id; // id[v] = id of strong component containing v privateint[] low; // low[v] = low number of v privateint pre; // preorder number counter privateint count; // number of strongly-connected components private Stack<Integer> stack;
//Computes the strong components of the digraph {@code G}. publicTarjanSCC(Digraph G) { marked = newboolean[G.V()]; stack = new Stack<Integer>(); id = newint[G.V()]; low = newint[G.V()]; for (int v = 0; v < G.V(); v++) { if (!marked[v]) dfs(G, v); }
// check that id[] gives strong components assertcheck(G); }
privatevoiddfs(Digraph G, int v) { marked[v] = true; low[v] = pre++; int min = low[v]; stack.push(v); for (int w : G.adj(v)) { if (!marked[w]) dfs(G, w); if (low[w] < min) min = low[w]; } if (min < low[v]) { low[v] = min; return; } int w; do { w = stack.pop(); id[w] = count; low[w] = G.V(); } while (w != v); count++; }
//Returns the number of strong components. publicintcount() { return count; }
// Are vertices {@code v} and {@code w} in the same strong component? publicbooleanstronglyConnected(int v, int w) { validateVertex(v); validateVertex(w); return id[v] == id[w]; }
//Returns the component id of the strong component containing vertex {@code v}. publicintid(int v) { validateVertex(v); return id[v]; }
// does the id[] array contain the strongly connected components? privatebooleancheck(Digraph G) { TransitiveClosure tc = new TransitiveClosure(G); for (int v = 0; v < G.V(); v++) { for (int w = 0; w < G.V(); w++) { if (stronglyConnected(v, w) != (tc.reachable(v, w) && tc.reachable(w, v))) returnfalse; } } returntrue; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = marked.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code TarjanSCC} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Digraph G = new Digraph(in); TarjanSCC scc = new TarjanSCC(G);
// number of connected components int m = scc.count(); StdOut.println(m + " components");
// compute list of vertices in each strong component Queue<Integer>[] components = (Queue<Integer>[]) new Queue[m]; for (int i = 0; i < m; i++) { components[i] = new Queue<Integer>(); } for (int v = 0; v < G.V(); v++) { components[scc.id(v)].enqueue(v); }
// print results for (int i = 0; i < m; i++) { for (int v : components[i]) { StdOut.print(v + " "); } StdOut.println(); } } }
publicclassTransitiveClosure { private DirectedDFS[] tc; // tc[v] = reachable from v
//Computes the transitive closure of the digraph {@code G}. publicTransitiveClosure(Digraph G) { tc = new DirectedDFS[G.V()]; for (int v = 0; v < G.V(); v++) tc[v] = new DirectedDFS(G, v); }
//Is there a directed path from vertex {@code v} to vertex {@code w} in the digraph? publicbooleanreachable(int v, int w) { validateVertex(v); validateVertex(w); return tc[v].marked(w); }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = tc.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code TransitiveClosure} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); Digraph G = new Digraph(in);
TransitiveClosure tc = new TransitiveClosure(G);
// print header StdOut.print(" "); for (int v = 0; v < G.V(); v++) StdOut.printf("%3d", v); StdOut.println(); StdOut.println("--------------------------------------------");
// print transitive closure for (int v = 0; v < G.V(); v++) { StdOut.printf("%3d: ", v); for (int w = 0; w < G.V(); w++) { if (tc.reachable(v, w)) StdOut.printf(" T"); else StdOut.printf(" "); } StdOut.println(); } }
publicEdge(int v, int w, double weight) { if (v < 0) thrownew IllegalArgumentException("vertex index must be a nonnegative integer"); if (w < 0) thrownew IllegalArgumentException("vertex index must be a nonnegative integer"); if (Double.isNaN(weight)) thrownew IllegalArgumentException("Weight is NaN"); this.v = v; this.w = w; this.weight = weight; }
publicdoubleweight() { return weight; }
//Returns either endpoint of this edge. publicinteither() { return v; }
//Returns the endpoint of this edge that is different from the given vertex. publicintother(int vertex){ if (vertex == v) return w; elseif (vertex == w) return v; elsethrownew IllegalArgumentException("Illegal endpoint"); }
//Compares two edges by weight. @Override publicintcompareTo(Edge that) { return Double.compare(this.weight, that.weight); }
privatefinalint V; privateint E; private Bag<Edge>[] adj; //Initializes an empty edge-weighted graph with {@code V} vertices and 0 edges. publicEdgeWeightedGraph(int V) { if (V < 0) thrownew IllegalArgumentException("Number of vertices must be nonnegative"); this.V = V; this.E = 0; adj = (Bag<Edge>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<Edge>(); }
//Initializes a random edge-weighted graph with {@code V} vertices and <em>E</em> edges. publicEdgeWeightedGraph(int V, int E) { this(V); if (E < 0) thrownew IllegalArgumentException("Number of edges must be nonnegative"); for (int i = 0; i < E; i++) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); double weight = Math.round(100 * StdRandom.uniform()) / 100.0; Edge e = new Edge(v, w, weight); addEdge(e); } }
//Initializes an edge-weighted graph from an input stream. publicEdgeWeightedGraph(In in) { if (in == null) thrownew IllegalArgumentException("argument is null");
try { V = in.readInt(); adj = (Bag<Edge>[]) new Bag[V]; for (int v = 0; v < V; v++) { adj[v] = new Bag<Edge>(); }
int E = in.readInt(); if (E < 0) thrownew IllegalArgumentException("Number of edges must be nonnegative"); for (int i = 0; i < E; i++) { int v = in.readInt(); int w = in.readInt(); validateVertex(v); validateVertex(w); double weight = in.readDouble(); Edge e = new Edge(v, w, weight); addEdge(e); } } catch (NoSuchElementException e) { thrownew IllegalArgumentException("invalid input format in EdgeWeightedGraph constructor", e); }
}
//Initializes a new edge-weighted graph that is a deep copy of {@code G}. publicEdgeWeightedGraph(EdgeWeightedGraph G) { this(G.V()); this.E = G.E(); for (int v = 0; v < G.V(); v++) { // reverse so that adjacency list is in same order as original Stack<Edge> reverse = new Stack<Edge>(); for (Edge e : G.adj[v]) { reverse.push(e); } for (Edge e : reverse) { adj[v].add(e); } } }
publicintV() { return V; }
publicintE() { return E; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
//Adds the undirected edge {@code e} to this edge-weighted graph. publicvoidaddEdge(Edge e) { int v = e.either(); int w = e.other(v); validateVertex(v); validateVertex(w); adj[v].add(e); adj[w].add(e); E++; }
//Returns the edges incident on vertex {@code v}. public Iterable<Edge> adj(int v) { validateVertex(v); return adj[v]; }
//Returns the degree of vertex {@code v}. publicintdegree(int v) { validateVertex(v); return adj[v].size(); }
//Returns all edges in this edge-weighted graph. public Iterable<Edge> edges() { Bag<Edge> list = new Bag<Edge>(); for (int v = 0; v < V; v++) { int selfLoops = 0; for (Edge e : adj(v)) { if (e.other(v) > v) { list.add(e); } // add only one copy of each self loop (self loops will be consecutive) elseif (e.other(v) == v) { if (selfLoops % 2 == 0) list.add(e); selfLoops++; } } } return list; }
public String toString() { StringBuilder s = new StringBuilder(); s.append(V + " " + E + NEWLINE); for (int v = 0; v < V; v++) { s.append(v + ": "); for (Edge e : adj[v]) { s.append(e + " "); } s.append(NEWLINE); } return s.toString(); } }
privatedouble weight; // total weight of MST private Queue<Edge> mst; // edges in the MST privateboolean[] marked; // marked[v] = true iff v on tree private MinPQ<Edge> pq; // edges with one endpoint in tree
//Compute a minimum spanning tree (or forest) of an edge-weighted graph. publicLazyPrimMST(EdgeWeightedGraph G) { mst = new Queue<Edge>(); pq = new MinPQ<Edge>(); marked = newboolean[G.V()]; for (int v = 0; v < G.V(); v++) // run Prim from all vertices to if (!marked[v]) prim(G, v); // get a minimum spanning forest
// check optimality conditions assertcheck(G); }
// run Prim's algorithm privatevoidprim(EdgeWeightedGraph G, int s) { scan(G, s); while (!pq.isEmpty()) { // better to stop when mst has V-1 edges Edge e = pq.delMin(); // smallest edge on pq int v = e.either(), w = e.other(v); // two endpoints assert marked[v] || marked[w]; if (marked[v] && marked[w]) continue; // lazy, both v and w already scanned mst.enqueue(e); // add e to MST weight += e.weight(); if (!marked[v]) scan(G, v); // v becomes part of tree if (!marked[w]) scan(G, w); // w becomes part of tree } }
// add all edges e incident to v onto pq if the other endpoint has not yet been scanned privatevoidscan(EdgeWeightedGraph G, int v) { assert !marked[v]; marked[v] = true; for (Edge e : G.adj(v)) if (!marked[e.other(v)]) pq.insert(e); }
//Returns the edges in a minimum spanning tree (or forest). public Iterable<Edge> edges() { return mst; }
//Returns the sum of the edge weights in a minimum spanning tree (or forest). publicdoubleweight() { return weight; }
// check optimality conditions (takes time proportional to E V lg* V) privatebooleancheck(EdgeWeightedGraph G) {
// check weight double totalWeight = 0.0; for (Edge e : edges()) { totalWeight += e.weight(); } if (Math.abs(totalWeight - weight()) > FLOATING_POINT_EPSILON) { System.err.printf("Weight of edges does not equal weight(): %f vs. %f\n", totalWeight, weight()); returnfalse; }
// check that it is acyclic UF uf = new UF(G.V()); //UF见《数据结构-并查集 》 for (Edge e : edges()) { int v = e.either(), w = e.other(v); if (uf.find(v) == uf.find(w)) { System.err.println("Not a forest"); returnfalse; } uf.union(v, w); }
// check that it is a spanning forest for (Edge e : G.edges()) { int v = e.either(), w = e.other(v); if (uf.find(v) != uf.find(w)) { System.err.println("Not a spanning forest"); returnfalse; } }
// check that it is a minimal spanning forest (cut optimality conditions) for (Edge e : edges()) {
// all edges in MST except e uf = new UF(G.V()); for (Edge f : mst) { int x = f.either(), y = f.other(x); if (f != e) uf.union(x, y); }
// check that e is min weight edge in crossing cut for (Edge f : G.edges()) { int x = f.either(), y = f.other(x); if (uf.find(x) != uf.find(y)) { if (f.weight() < e.weight()) { System.err.println("Edge " + f + " violates cut optimality conditions"); returnfalse; } } }
}
returntrue; }
/** * Unit tests the {@code LazyPrimMST} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); EdgeWeightedGraph G = new EdgeWeightedGraph(in); LazyPrimMST mst = new LazyPrimMST(G); for (Edge e : mst.edges()) { StdOut.println(e); } StdOut.printf("%.5f\n", mst.weight()); }
private Edge[] edgeTo; // edgeTo[v] = shortest edge from tree vertex to non-tree vertex privatedouble[] distTo; // distTo[v] = weight of shortest such edge privateboolean[] marked; // marked[v] = true if v on tree, false otherwise private IndexMinPQ<Double> pq;
//Compute a minimum spanning tree (or forest) of an edge-weighted graph. publicPrimMST(EdgeWeightedGraph G) { edgeTo = new Edge[G.V()]; distTo = newdouble[G.V()]; marked = newboolean[G.V()]; pq = new IndexMinPQ<Double>(G.V()); for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY;
for (int v = 0; v < G.V(); v++) // run from each vertex to find if (!marked[v]) prim(G, v); // minimum spanning forest
// check optimality conditions assertcheck(G); }
// run Prim's algorithm in graph G, starting from vertex s privatevoidprim(EdgeWeightedGraph G, int s) { distTo[s] = 0.0; pq.insert(s, distTo[s]); while (!pq.isEmpty()) { int v = pq.delMin(); scan(G, v); } }
// scan vertex v privatevoidscan(EdgeWeightedGraph G, int v) { marked[v] = true; for (Edge e : G.adj(v)) { int w = e.other(v); if (marked[w]) continue; // v-w is obsolete edge if (e.weight() < distTo[w]) { distTo[w] = e.weight(); edgeTo[w] = e; if (pq.contains(w)) pq.decreaseKey(w, distTo[w]); else pq.insert(w, distTo[w]); } } }
//Returns the edges in a minimum spanning tree (or forest). public Iterable<Edge> edges() { Queue<Edge> mst = new Queue<Edge>(); for (int v = 0; v < edgeTo.length; v++) { Edge e = edgeTo[v]; if (e != null) { mst.enqueue(e); } } return mst; }
//Returns the sum of the edge weights in a minimum spanning tree (or forest). publicdoubleweight() { double weight = 0.0; for (Edge e : edges()) weight += e.weight(); return weight; }
// check optimality conditions (takes time proportional to E V lg* V) privatebooleancheck(EdgeWeightedGraph G) {
// check weight double totalWeight = 0.0; for (Edge e : edges()) { totalWeight += e.weight(); } if (Math.abs(totalWeight - weight()) > FLOATING_POINT_EPSILON) { System.err.printf("Weight of edges does not equal weight(): %f vs. %f\n", totalWeight, weight()); returnfalse; }
// check that it is acyclic UF uf = new UF(G.V()); for (Edge e : edges()) { int v = e.either(), w = e.other(v); if (uf.find(v) == uf.find(w)) { System.err.println("Not a forest"); returnfalse; } uf.union(v, w); }
// check that it is a spanning forest for (Edge e : G.edges()) { int v = e.either(), w = e.other(v); if (uf.find(v) != uf.find(w)) { System.err.println("Not a spanning forest"); returnfalse; } }
// check that it is a minimal spanning forest (cut optimality conditions) for (Edge e : edges()) {
// all edges in MST except e uf = new UF(G.V()); for (Edge f : edges()) { int x = f.either(), y = f.other(x); if (f != e) uf.union(x, y); }
// check that e is min weight edge in crossing cut for (Edge f : G.edges()) { int x = f.either(), y = f.other(x); if (uf.find(x) != uf.find(y)) { if (f.weight() < e.weight()) { System.err.println("Edge " + f + " violates cut optimality conditions"); returnfalse; } } }
}
returntrue; }
/** * Unit tests the {@code PrimMST} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args){ In in = new In(args[0]); EdgeWeightedGraph G = new EdgeWeightedGraph(in); PrimMST mst = new PrimMST(G); for (Edge e : mst.edges()) { StdOut.println(e); } StdOut.printf("%.5f\n", mst.weight()); }
privatedouble weight; // weight of MST private Queue<Edge> mst = new Queue<Edge>(); // edges in MST
//Compute a minimum spanning tree (or forest) of an edge-weighted graph. publicKruskalMST(EdgeWeightedGraph G) { // more efficient to build heap by passing array of edges MinPQ<Edge> pq = new MinPQ<Edge>(); for (Edge e : G.edges()) { pq.insert(e); }
// run greedy algorithm UF uf = new UF(G.V()); while (!pq.isEmpty() && mst.size() < G.V() - 1) { Edge e = pq.delMin(); int v = e.either(); int w = e.other(v); if (uf.find(v) != uf.find(w)) { // v-w does not create a cycle uf.union(v, w); // merge v and w components mst.enqueue(e); // add edge e to mst weight += e.weight(); } }
// check optimality conditions assertcheck(G); }
//Returns the edges in a minimum spanning tree (or forest). public Iterable<Edge> edges() { return mst; }
//Returns the sum of the edge weights in a minimum spanning tree (or forest). publicdoubleweight() { return weight; } // check optimality conditions (takes time proportional to E V lg* V) privatebooleancheck(EdgeWeightedGraph G) {
// check total weight double total = 0.0; for (Edge e : edges()) { total += e.weight(); } if (Math.abs(total - weight()) > FLOATING_POINT_EPSILON) { System.err.printf("Weight of edges does not equal weight(): %f vs. %f\n", total, weight()); returnfalse; }
// check that it is acyclic UF uf = new UF(G.V()); for (Edge e : edges()) { int v = e.either(), w = e.other(v); if (uf.find(v) == uf.find(w)) { System.err.println("Not a forest"); returnfalse; } uf.union(v, w); }
// check that it is a spanning forest for (Edge e : G.edges()) { int v = e.either(), w = e.other(v); if (uf.find(v) != uf.find(w)) { System.err.println("Not a spanning forest"); returnfalse; } }
// check that it is a minimal spanning forest (cut optimality conditions) for (Edge e : edges()) {
// all edges in MST except e uf = new UF(G.V()); for (Edge f : mst) { int x = f.either(), y = f.other(x); if (f != e) uf.union(x, y); } // check that e is min weight edge in crossing cut for (Edge f : G.edges()) { int x = f.either(), y = f.other(x); if (uf.find(x) != uf.find(y)) { if (f.weight() < e.weight()) { System.err.println("Edge " + f + " violates cut optimality conditions"); returnfalse; } } }
/** * Initializes a directed edge from vertex {@code v} to vertex {@code w} with * the given {@code weight}. */ publicDirectedEdge(int v, int w, double weight) { if (v < 0) thrownew IllegalArgumentException("Vertex names must be nonnegative integers"); if (w < 0) thrownew IllegalArgumentException("Vertex names must be nonnegative integers"); if (Double.isNaN(weight)) thrownew IllegalArgumentException("Weight is NaN"); this.v = v; this.w = w; this.weight = weight; }
//Returns the tail vertex of the directed edge. publicintfrom() { return v; }
//Returns the head vertex of the directed edge. publicintto() { return w; }
//Returns the weight of the directed edge. publicdoubleweight() { return weight; }
//Returns a string representation of the directed edge. public String toString() { return v + "->" + w + " " + String.format("%5.2f", weight); }
privatefinalint V; // number of vertices in this digraph privateint E; // number of edges in this digraph private Bag<DirectedEdge>[] adj; // adj[v] = adjacency list for vertex v privateint[] indegree; // indegree[v] = indegree of vertex v //Initializes an empty edge-weighted digraph with {@code V} vertices and 0 edges. publicEdgeWeightedDigraph(int V) { if (V < 0) thrownew IllegalArgumentException("Number of vertices in a Digraph must be nonnegative"); this.V = V; this.E = 0; this.indegree = newint[V]; adj = (Bag<DirectedEdge>[]) new Bag[V]; for (int v = 0; v < V; v++) adj[v] = new Bag<DirectedEdge>(); }
//Initializes a random edge-weighted digraph with {@code V} vertices and <em>E</em> edges. publicEdgeWeightedDigraph(int V, int E) { this(V); if (E < 0) thrownew IllegalArgumentException("Number of edges in a Digraph must be nonnegative"); for (int i = 0; i < E; i++) { int v = StdRandom.uniform(V); int w = StdRandom.uniform(V); double weight = 0.01 * StdRandom.uniform(100); DirectedEdge e = new DirectedEdge(v, w, weight); addEdge(e); } }
/** * /Initializes an edge-weighted digraph from the specified input stream. * The format is the number of vertices <em>V</em>, * followed by the number of edges <em>E</em>, * followed by <em>E</em> pairs of vertices and edge weights, * with each entry separated by whitespace. */ publicEdgeWeightedDigraph(In in) { if (in == null) thrownew IllegalArgumentException("argument is null"); try { this.V = in.readInt(); if (V < 0) thrownew IllegalArgumentException("number of vertices in a Digraph must be nonnegative"); indegree = newint[V]; adj = (Bag<DirectedEdge>[]) new Bag[V]; for (int v = 0; v < V; v++) { adj[v] = new Bag<DirectedEdge>(); }
int E = in.readInt(); if (E < 0) thrownew IllegalArgumentException("Number of edges must be nonnegative"); for (int i = 0; i < E; i++) { int v = in.readInt(); int w = in.readInt(); validateVertex(v); validateVertex(w); double weight = in.readDouble(); addEdge(new DirectedEdge(v, w, weight)); } } catch (NoSuchElementException e) { thrownew IllegalArgumentException("invalid input format in EdgeWeightedDigraph constructor", e); } }
//Initializes a new edge-weighted digraph that is a deep copy of {@code G}. publicEdgeWeightedDigraph(EdgeWeightedDigraph G) { this(G.V()); this.E = G.E(); for (int v = 0; v < G.V(); v++) this.indegree[v] = G.indegree(v); for (int v = 0; v < G.V(); v++) { // reverse so that adjacency list is in same order as original Stack<DirectedEdge> reverse = new Stack<DirectedEdge>(); for (DirectedEdge e : G.adj[v]) { reverse.push(e); } for (DirectedEdge e : reverse) { adj[v].add(e); } } }
//Returns the number of vertices in this edge-weighted digraph. publicintV() { return V; }
//Returns the number of edges in this edge-weighted digraph. publicintE() { return E; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
//Adds the directed edge {@code e} to this edge-weighted digraph. publicvoidaddEdge(DirectedEdge e) { int v = e.from(); int w = e.to(); validateVertex(v); validateVertex(w); adj[v].add(e); indegree[w]++; E++; }
//Returns the directed edges incident from vertex {@code v}. public Iterable<DirectedEdge> adj(int v) { validateVertex(v); return adj[v]; }
//Returns the number of directed edges incident from vertex {@code v}. publicintoutdegree(int v) { validateVertex(v); return adj[v].size(); }
//Returns the number of directed edges incident to vertex {@code v}. publicintindegree(int v) { validateVertex(v); return indegree[v]; }
//Returns all directed edges in this edge-weighted digraph. public Iterable<DirectedEdge> edges() { Bag<DirectedEdge> list = new Bag<DirectedEdge>(); for (int v = 0; v < V; v++) { for (DirectedEdge e : adj(v)) { list.add(e); } } return list; }
//Returns a string representation of this edge-weighted digraph. public String toString() { StringBuilder s = new StringBuilder(); s.append(V + " " + E + NEWLINE); for (int v = 0; v < V; v++) { s.append(v + ": "); for (DirectedEdge e : adj[v]) s.append(e + " "); s.append(NEWLINE); } return s.toString(); } }
publicclassDijkstraSP { privatedouble[] distTo; // distTo[v] = distance of shortest s->v path private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path private IndexMinPQ<Double> pq; // priority queue of vertices
/** * Computes a shortest-paths tree from the source vertex {@code s} to every other * vertex in the edge-weighted digraph {@code G}. */ publicDijkstraSP(EdgeWeightedDigraph G, int s) { for (DirectedEdge e : G.edges()) { if (e.weight() < 0) thrownew IllegalArgumentException("edge " + e + " has negative weight"); }
distTo = newdouble[G.V()]; edgeTo = new DirectedEdge[G.V()];
validateVertex(s);
for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY; distTo[s] = 0.0;
// relax vertices in order of distance from s pq = new IndexMinPQ<Double>(G.V()); pq.insert(s, distTo[s]); while (!pq.isEmpty()) { int v = pq.delMin(); for (DirectedEdge e : G.adj(v)) relax(e); }
// relax edge e and update pq if changed privatevoidrelax(DirectedEdge e) { int v = e.from(), w = e.to(); if (distTo[w] > distTo[v] + e.weight()) { distTo[w] = distTo[v] + e.weight(); edgeTo[w] = e; if (pq.contains(w)) pq.decreaseKey(w, distTo[w]); else pq.insert(w, distTo[w]); } }
//Returns the length of a shortest path from the source vertex {@code s} to vertex {@code v}. publicdoubledistTo(int v) { validateVertex(v); return distTo[v]; }
//Returns true if there is a path from the source vertex {@code s} to vertex {@code v}. publicbooleanhasPathTo(int v) { validateVertex(v); return distTo[v] < Double.POSITIVE_INFINITY; }
//Returns a shortest path from the source vertex {@code s} to vertex {@code v}. public Iterable<DirectedEdge> pathTo(int v) { validateVertex(v); if (!hasPathTo(v)) returnnull; Stack<DirectedEdge> path = new Stack<DirectedEdge>(); for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) { path.push(e); } return path; }
// check optimality conditions: // (i) for all edges e: distTo[e.to()] <= distTo[e.from()] + e.weight() // (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight() privatebooleancheck(EdgeWeightedDigraph G, int s){
// check that edge weights are nonnegative for (DirectedEdge e : G.edges()) { if (e.weight() < 0) { System.err.println("negative edge weight detected"); returnfalse; } }
// check that distTo[v] and edgeTo[v] are consistent if (distTo[s] != 0.0 || edgeTo[s] != null) { System.err.println("distTo[s] and edgeTo[s] inconsistent"); returnfalse; } for (int v = 0; v < G.V(); v++) { if (v == s) continue; if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) { System.err.println("distTo[] and edgeTo[] inconsistent"); returnfalse; } }
// check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() for (int v = 0; v < G.V(); v++) { for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (distTo[v] + e.weight() < distTo[w]) { System.err.println("edge " + e + " not relaxed"); returnfalse; } } }
// check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (int w = 0; w < G.V(); w++) { if (edgeTo[w] == null) continue; DirectedEdge e = edgeTo[w]; int v = e.from(); if (w != e.to()) returnfalse; if (distTo[v] + e.weight() != distTo[w]) { System.err.println("edge " + e + " on shortest path not tight"); returnfalse; } } returntrue; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = distTo.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code DijkstraSP} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args){ In in = new In(args[0]); EdgeWeightedDigraph G = new EdgeWeightedDigraph(in); int s = Integer.parseInt(args[1]);
// compute shortest paths DijkstraSP sp = new DijkstraSP(G, s);
// print shortest path for (int t = 0; t < G.V(); t++) { if (sp.hasPathTo(t)) { StdOut.printf("%d to %d (%.2f) ", s, t, sp.distTo(t)); for (DirectedEdge e : sp.pathTo(t)) { StdOut.print(e + " "); } StdOut.println(); } else { StdOut.printf("%d to %d no path\n", s, t); } } }
}
测试
1 2 3 4 5 6 7
* % java DijkstraSP mediumEWD.txt 0 * 0 to 0 (0.00) * 0 to 1 (0.71) 0->440.0644->930.07 ... 107->10.07 * 0 to 2 (0.65) 0->440.0644->2310.10 ... 42->20.11 * 0 to 3 (0.46) 0->970.0897->2480.09 ... 45->30.12 * 0 to 4 (0.42) 0->440.0644->930.07 ... 77->40.11 * ...
publicclassAcyclicSP { privatedouble[] distTo; // distTo[v] = distance of shortest s->v path private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path
/** * Computes a shortest paths tree from {@code s} to every other vertex in * the directed acyclic graph {@code G}. */ publicAcyclicSP(EdgeWeightedDigraph G, int s) { distTo = newdouble[G.V()]; edgeTo = new DirectedEdge[G.V()];
validateVertex(s);
for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY; distTo[s] = 0.0;
// visit vertices in topological order Topological topological = new Topological(G); if (!topological.hasOrder()) thrownew IllegalArgumentException("Digraph is not acyclic."); for (int v : topological.order()) { for (DirectedEdge e : G.adj(v)) relax(e); } }
// relax edge e privatevoidrelax(DirectedEdge e) { int v = e.from(), w = e.to(); if (distTo[w] > distTo[v] + e.weight()) { distTo[w] = distTo[v] + e.weight(); edgeTo[w] = e; } }
//Returns the length of a shortest path from the source vertex {@code s} to vertex {@code v}. publicdoubledistTo(int v) { validateVertex(v); return distTo[v]; }
//Is there a path from the source vertex {@code s} to vertex {@code v}? publicbooleanhasPathTo(int v) { validateVertex(v); return distTo[v] < Double.POSITIVE_INFINITY; }
//Returns a shortest path from the source vertex {@code s} to vertex {@code v}. public Iterable<DirectedEdge> pathTo(int v) { validateVertex(v); if (!hasPathTo(v)) returnnull; Stack<DirectedEdge> path = new Stack<DirectedEdge>(); for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) { path.push(e); } return path; }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = distTo.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code AcyclicSP} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); int s = Integer.parseInt(args[1]); EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
// find shortest path from s to each other vertex in DAG AcyclicSP sp = new AcyclicSP(G, s); for (int v = 0; v < G.V(); v++) { if (sp.hasPathTo(v)) { StdOut.printf("%d to %d (%.2f) ", s, v, sp.distTo(v)); for (DirectedEdge e : sp.pathTo(v)) { StdOut.print(e + " "); } StdOut.println(); } else { StdOut.printf("%d to %d no path\n", s, v); } } } }
测试
1 2 3 4 5 6 7 8 9
* % java AcyclicSP tinyEWDAG.txt 5 * 5 to 0 (0.73) 5->40.354->00.38 * 5 to 1 (0.32) 5->10.32 * 5 to 2 (0.62) 5->70.287->20.34 * 5 to 3 (0.61) 5->10.321->30.29 * 5 to 4 (0.35) 5->40.35 * 5 to 5 (0.00) * 5 to 6 (1.13) 5->10.321->30.293->60.52 * 5 to 7 (0.28) 5->70.28
// this class cannot be instantiated privateCPM(){ }
/** * Reads the precedence constraints from standard input * and prints a feasible schedule to standard output. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) {
// number of jobs int n = StdIn.readInt();
// source and sink int source = 2 * n; int sink = 2 * n + 1;
// build network EdgeWeightedDigraph G = new EdgeWeightedDigraph(2 * n + 2); for (int i = 0; i < n; i++) { double duration = StdIn.readDouble(); G.addEdge(new DirectedEdge(source, i, 0.0)); G.addEdge(new DirectedEdge(i + n, sink, 0.0)); G.addEdge(new DirectedEdge(i, i + n, duration));
// precedence constraints int m = StdIn.readInt(); for (int j = 0; j < m; j++) { int precedent = StdIn.readInt(); G.addEdge(new DirectedEdge(n + i, precedent, 0.0)); } }
// compute longest path AcyclicLP lp = new AcyclicLP(G, source);//AcyclicLP只需将AcyclicSP稍作修改即可
// print results StdOut.println(" job start finish"); StdOut.println("--------------------"); for (int i = 0; i < n; i++) { StdOut.printf("%4d %7.1f %7.1f\n", i, lp.distTo(i), lp.distTo(i+n)); } StdOut.printf("Finish time: %7.1f\n", lp.distTo(sink)); }
publicclassBellmanFordSP { privatedouble[] distTo; // distTo[v] = distance of shortest s->v path private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path privateboolean[] onQueue; // onQueue[v] = is v currently on the queue? private Queue<Integer> queue; // queue of vertices to relax privateint cost; // number of calls to relax() private Iterable<DirectedEdge> cycle; // negative cycle (or null if no such cycle)
/** * Computes a shortest paths tree from {@code s} to every other vertex in * the edge-weighted digraph {@code G}. */ publicBellmanFordSP(EdgeWeightedDigraph G, int s) { distTo = newdouble[G.V()]; edgeTo = new DirectedEdge[G.V()]; onQueue = newboolean[G.V()]; for (int v = 0; v < G.V(); v++) distTo[v] = Double.POSITIVE_INFINITY; distTo[s] = 0.0;
// Bellman-Ford algorithm queue = new Queue<Integer>(); queue.enqueue(s); onQueue[s] = true; while (!queue.isEmpty() && !hasNegativeCycle()) { int v = queue.dequeue(); onQueue[v] = false; relax(G, v); }
assertcheck(G, s); }
// relax vertex v and put other endpoints on queue if changed privatevoidrelax(EdgeWeightedDigraph G, int v) { for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (distTo[w] > distTo[v] + e.weight()) { distTo[w] = distTo[v] + e.weight(); edgeTo[w] = e; if (!onQueue[w]) { queue.enqueue(w); onQueue[w] = true; } } if (++cost % G.V() == 0) { findNegativeCycle(); if (hasNegativeCycle()) return; // found a negative cycle } } }
//Is there a negative cycle reachable from the source vertex {@code s}? publicbooleanhasNegativeCycle() { return cycle != null; }
/** * Returns a negative cycle reachable from the source vertex {@code s}, or {@code null} * if there is no such cycle. */ public Iterable<DirectedEdge> negativeCycle() { return cycle; }
// by finding a cycle in predecessor graph privatevoidfindNegativeCycle(){ int V = edgeTo.length; EdgeWeightedDigraph spt = new EdgeWeightedDigraph(V); for (int v = 0; v < V; v++) if (edgeTo[v] != null) spt.addEdge(edgeTo[v]);
EdgeWeightedDirectedCycle finder = new EdgeWeightedDirectedCycle(spt); cycle = finder.cycle(); }
//Returns the length of a shortest path from the source vertex {@code s} to vertex {@code v}. publicdoubledistTo(int v) { validateVertex(v); if (hasNegativeCycle()) thrownew UnsupportedOperationException("Negative cost cycle exists"); return distTo[v]; }
//Is there a path from the source {@code s} to vertex {@code v}? publicbooleanhasPathTo(int v) { validateVertex(v); return distTo[v] < Double.POSITIVE_INFINITY; }
//Returns a shortest path from the source {@code s} to vertex {@code v}. public Iterable<DirectedEdge> pathTo(int v) { validateVertex(v); if (hasNegativeCycle()) thrownew UnsupportedOperationException("Negative cost cycle exists"); if (!hasPathTo(v)) returnnull; Stack<DirectedEdge> path = new Stack<DirectedEdge>(); for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) { path.push(e); } return path; }
// check optimality conditions: either // (i) there exists a negative cycle reacheable from s // or // (ii) for all edges e = v->w: distTo[w] <= distTo[v] + e.weight() // (ii') for all edges e = v->w on the SPT: distTo[w] == distTo[v] + e.weight() privatebooleancheck(EdgeWeightedDigraph G, int s) {
// has a negative cycle if (hasNegativeCycle()) { double weight = 0.0; for (DirectedEdge e : negativeCycle()) { weight += e.weight(); } if (weight >= 0.0) { System.err.println("error: weight of negative cycle = " + weight); returnfalse; } }
// no negative cycle reachable from source else {
// check that distTo[v] and edgeTo[v] are consistent if (distTo[s] != 0.0 || edgeTo[s] != null) { System.err.println("distanceTo[s] and edgeTo[s] inconsistent"); returnfalse; } for (int v = 0; v < G.V(); v++) { if (v == s) continue; if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) { System.err.println("distTo[] and edgeTo[] inconsistent"); returnfalse; } }
// check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight() for (int v = 0; v < G.V(); v++) { for (DirectedEdge e : G.adj(v)) { int w = e.to(); if (distTo[v] + e.weight() < distTo[w]) { System.err.println("edge " + e + " not relaxed"); returnfalse; } } }
// check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight() for (int w = 0; w < G.V(); w++) { if (edgeTo[w] == null) continue; DirectedEdge e = edgeTo[w]; int v = e.from(); if (w != e.to()) returnfalse; if (distTo[v] + e.weight() != distTo[w]) { System.err.println("edge " + e + " on shortest path not tight"); returnfalse; } } }
// throw an IllegalArgumentException unless {@code 0 <= v < V} privatevoidvalidateVertex(int v) { int V = distTo.length; if (v < 0 || v >= V) thrownew IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); }
/** * Unit tests the {@code BellmanFordSP} data type. * * @param args the command-line arguments */ publicstaticvoidmain(String[] args) { In in = new In(args[0]); int s = Integer.parseInt(args[1]); EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
BellmanFordSP sp = new BellmanFordSP(G, s);
// print negative cycle if (sp.hasNegativeCycle()) { for (DirectedEdge e : sp.negativeCycle()) StdOut.println(e); }
// print shortest paths else { for (int v = 0; v < G.V(); v++) { if (sp.hasPathTo(v)) { StdOut.printf("%d to %d (%5.2f) ", s, v, sp.distTo(v)); for (DirectedEdge e : sp.pathTo(v)) { StdOut.print(e + " "); } StdOut.println(); } else { StdOut.printf("%d to %d no path\n", s, v); } } }