diff --git a/README.md b/README.md index 95482aec3..22a934dd3 100644 --- a/README.md +++ b/README.md @@ -216,14 +216,12 @@ $ java -cp classes com.williamfiset.algorithms.search.BinarySearch - [:movie_camera:](https://www.youtube.com/watch?v=4NQ3HnhyNfQ) [Floyd Warshall algorithm (adjacency matrix, negative cycle check)](src/main/java/com/williamfiset/algorithms/graphtheory/FloydWarshallSolver.java) **- O(V3)** - [:movie_camera:](https://www.youtube.com/watch?v=cIBFEhD77b4) [Kahn's algorithm (topological sort, adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/Kahns.java) **- O(E+V)** - [Kruskal's min spanning tree algorithm (edge list, union find)](src/main/java/com/williamfiset/algorithms/graphtheory/KruskalsEdgeList.java) **- O(Elog(E))** -- [:movie_camera:](https://www.youtube.com/watch?v=JZBQLXgSGfs) [Kruskal's min spanning tree algorithm (edge list, union find, lazy sorting)](src/main/java/com/williamfiset/algorithms/graphtheory/KruskalsEdgeListPartialSortSolver.java) **- O(Elog(E))** - [Kosaraju's strongly connected components algorithm (adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/Kosaraju.java) **- O(V+E)** - [:movie_camera:](https://www.youtube.com/watch?v=jsmMtJpPnhU) [Prim's min spanning tree algorithm (lazy version, adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/LazyPrimsAdjacencyList.java) **- O(Elog(E))** - [:movie_camera:](https://www.youtube.com/watch?v=xq3ABa-px_g) [Prim's min spanning tree algorithm (eager version, adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/EagerPrimsAdjacencyList.java) **- O(Elog(V))** - [Steiner tree (minimum spanning tree generalization)](src/main/java/com/williamfiset/algorithms/graphtheory/SteinerTree.java) **- O(V3 + V2 _ 2T + V _ 3T)** - [:movie_camera:](https://www.youtube.com/watch?v=wUgWX0nc4NY) [Tarjan's strongly connected components algorithm (adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/TarjanSccSolverAdjacencyList.java) **- O(V+E)** - [:movie_camera:](https://www.youtube.com/watch?v=eL-KzMXSXXI) [Topological sort (acyclic graph, adjacency list)](src/main/java/com/williamfiset/algorithms/graphtheory/TopologicalSortAdjacencyList.java) **- O(V+E)** -- [Traveling Salesman Problem (brute force)](src/main/java/com/williamfiset/algorithms/graphtheory/TspBruteForce.java) **- O(n!)** - [:movie_camera:](https://www.youtube.com/watch?v=cY4HiiFHO1o) [Traveling Salesman Problem (dynamic programming, iterative)](src/main/java/com/williamfiset/algorithms/graphtheory/TspDynamicProgrammingIterative.java) **- O(n22n)** - [Traveling Salesman Problem (dynamic programming, recursive)](src/main/java/com/williamfiset/algorithms/graphtheory/TspDynamicProgrammingRecursive.java) **- O(n22n)** diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/BUILD b/src/main/java/com/williamfiset/algorithms/graphtheory/BUILD index 4a5e0ef1f..6d006c116 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/BUILD +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/BUILD @@ -160,13 +160,6 @@ java_binary( runtime_deps = [":graphtheory"], ) -# bazel run //src/main/java/com/williamfiset/algorithms/graphtheory:KruskalsEdgeListPartialSortSolver -java_binary( - name = "KruskalsEdgeListPartialSortSolver", - main_class = "com.williamfiset.algorithms.graphtheory.KruskalsEdgeListPartialSortSolver", - runtime_deps = [":graphtheory"], -) - # bazel run //src/main/java/com/williamfiset/algorithms/graphtheory:LazyPrimsAdjacencyList java_binary( name = "LazyPrimsAdjacencyList", @@ -181,12 +174,6 @@ java_binary( runtime_deps = [":graphtheory"], ) -# bazel run //src/main/java/com/williamfiset/algorithms/graphtheory:TarjanAdjacencyMatrix -java_binary( - name = "TarjanAdjacencyMatrix", - main_class = "com.williamfiset.algorithms.graphtheory.TarjanAdjacencyMatrix", - runtime_deps = [":graphtheory"], -) # bazel run //src/main/java/com/williamfiset/algorithms/graphtheory:TarjanSccSolverAdjacencyList java_binary( diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/KruskalsEdgeListPartialSortSolver.java b/src/main/java/com/williamfiset/algorithms/graphtheory/KruskalsEdgeListPartialSortSolver.java deleted file mode 100644 index b3a651014..000000000 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/KruskalsEdgeListPartialSortSolver.java +++ /dev/null @@ -1,196 +0,0 @@ -/** - * An implementation of Kruskal's MST algorithm with lazy sorting. - * - *

Tested against: - https://open.kattis.com/problems/minspantree - * - *

Time Complexity: O(Elog(E)) - * - * @author William Fiset, william.alexandre.fiset@gmail.com - */ -package com.williamfiset.algorithms.graphtheory; - -import java.util.ArrayList; -import java.util.List; -import java.util.PriorityQueue; - -public class KruskalsEdgeListPartialSortSolver { - - static class Edge implements Comparable { - int u, v, cost; - - // 'u' and 'v' are nodes indexes and 'cost' is the cost of taking this edge. - public Edge(int u, int v, int cost) { - this.u = u; - this.v = v; - this.cost = cost; - } - - // Sort edges based on cost. - @Override - public int compareTo(Edge other) { - return cost - other.cost; - } - } - - // Inputs - private int n; - private List edges; - - // Internal - private boolean solved; - private boolean mstExists; - - // Outputs - private Edge[] mst; - private long mstCost; - - // edges - A list of undirected edges. - // n - The number of nodes in the input graph. - public KruskalsEdgeListPartialSortSolver(List edges, int n) { - if (edges == null || n <= 1) throw new IllegalArgumentException(); - this.edges = edges; - this.n = n; - } - - // Gets the Minimum Spanning Tree (MST) of the input graph or null if no MST. - public Edge[] getMst() { - kruskals(); - return mstExists ? mst : null; - } - - // Gets the Minimum Spanning Tree (MST) cost or null if no MST exists. - public Long getMstCost() { - kruskals(); - return mstExists ? mstCost : null; - } - - private void kruskals() { - if (solved) return; - - // Heapify operation in constructor transforms list of edges into a binary heap in O(n) - PriorityQueue pq = new PriorityQueue<>(edges); - UnionFind uf = new UnionFind(n); - - int index = 0; - mst = new Edge[n - 1]; - - while (!pq.isEmpty()) { - // Use heap to poll the next cheapest edge. Polling avoids the need to sort - // the edges before loop in the event that the algorithm terminates early. - Edge edge = pq.poll(); - - // Skip this edge to avoid creating a cycle in MST. - if (uf.connected(edge.u, edge.v)) continue; - - // Include this edge - uf.union(edge.u, edge.v); - mstCost += edge.cost; - mst[index++] = edge; - - // Stop early if we found a MST that includes all the nodes. - if (uf.size(0) == n) break; - } - - mstExists = (uf.size(0) == n); - solved = true; - } - - // Union find data structure - private static class UnionFind { - private int[] id, sz; - - public UnionFind(int n) { - id = new int[n]; - sz = new int[n]; - for (int i = 0; i < n; i++) { - id[i] = i; - sz[i] = 1; - } - } - - public int find(int p) { - int root = p; - while (root != id[root]) root = id[root]; - // Path compression - while (p != root) { - int next = id[p]; - id[p] = root; - p = next; - } - return root; - } - - public boolean connected(int p, int q) { - return find(p) == find(q); - } - - public int size(int p) { - return sz[find(p)]; - } - - public void union(int p, int q) { - int root1 = find(p); - int root2 = find(q); - if (root1 == root2) return; - if (sz[root1] < sz[root2]) { - sz[root2] += sz[root1]; - id[root1] = root2; - } else { - sz[root1] += sz[root2]; - id[root2] = root1; - } - } - } - - /* Usage example: */ - - public static void main(String[] args) { - int numNodes = 10; - List edges = new ArrayList<>(); - - edges.add(new Edge(0, 1, 5)); - edges.add(new Edge(1, 2, 4)); - edges.add(new Edge(2, 9, 2)); - edges.add(new Edge(0, 4, 1)); - edges.add(new Edge(0, 3, 4)); - edges.add(new Edge(1, 3, 2)); - edges.add(new Edge(2, 7, 4)); - edges.add(new Edge(2, 8, 1)); - edges.add(new Edge(9, 8, 0)); - edges.add(new Edge(4, 5, 1)); - edges.add(new Edge(5, 6, 7)); - edges.add(new Edge(6, 8, 4)); - edges.add(new Edge(4, 3, 2)); - edges.add(new Edge(5, 3, 5)); - edges.add(new Edge(3, 6, 11)); - edges.add(new Edge(6, 7, 1)); - edges.add(new Edge(3, 7, 2)); - edges.add(new Edge(7, 8, 6)); - - KruskalsEdgeListPartialSortSolver solver; - solver = new KruskalsEdgeListPartialSortSolver(edges, numNodes); - Long cost = solver.getMstCost(); - - if (cost == null) { - System.out.println("No MST does not exists"); - } else { - System.out.println("MST cost: " + cost); - for (Edge e : solver.getMst()) { - System.out.println(String.format("Used edge (%d, %d) with cost: %d", e.u, e.v, e.cost)); - } - } - - // Output: - // MST cost: 14 - // Used edge (9, 8) with cost: 0 - // Used edge (2, 8) with cost: 1 - // Used edge (6, 7) with cost: 1 - // Used edge (0, 4) with cost: 1 - // Used edge (4, 5) with cost: 1 - // Used edge (3, 7) with cost: 2 - // Used edge (4, 3) with cost: 2 - // Used edge (1, 3) with cost: 2 - // Used edge (1, 2) with cost: 4 - - } -} diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanAdjacencyMatrix.java b/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanAdjacencyMatrix.java deleted file mode 100644 index a053ec2cc..000000000 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanAdjacencyMatrix.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * An implementation of Tarjan's SCC algorithm for a directed graph. Time Complexity: O(V^2) - * - * @author Micah Stairs - */ -package com.williamfiset.algorithms.graphtheory; - -import java.util.*; - -class TarjanAdjacencyMatrix { - - public static void main(String[] args) { - - // As an example we create a graph with four strongly connected components - - final int NUM_NODES = 10; - - boolean[][] adjMatrix = new boolean[NUM_NODES][NUM_NODES]; - - // SCC 1 with nodes 0,1,2 - adjMatrix[0][1] = true; - adjMatrix[1][2] = true; - adjMatrix[2][0] = true; - - // SCC 2 with nodes 3,4,5,6 - adjMatrix[5][4] = true; - adjMatrix[5][6] = true; - adjMatrix[3][5] = true; - adjMatrix[4][3] = true; - adjMatrix[4][5] = true; - adjMatrix[6][4] = true; - - // SCC 3 with nodes 7,8 - adjMatrix[7][8] = true; - adjMatrix[8][7] = true; - - // SCC 4 is node 9 all alone by itself - // Add a few more edges to make things interesting - adjMatrix[1][5] = true; - adjMatrix[1][7] = true; - adjMatrix[2][7] = true; - adjMatrix[6][8] = true; - adjMatrix[9][8] = true; - adjMatrix[9][4] = true; - - Tarjan sccs = new Tarjan(adjMatrix); - - System.out.println( - "Strong connected component count: " + sccs.countStronglyConnectedComponents()); - System.out.println( - "Strong connected components:\n" + Arrays.toString(sccs.getStronglyConnectedComponents())); - - // Output: - // Strong connected component count: 4 - // Strong connected components: - // [2, 2, 2, 1, 1, 1, 1, 0, 0, 3] - - } - - // Tarjan is used to find/count the Strongly Connected - // Components (SCCs) in a directed graph in O(V+E). - static class Tarjan { - - private int n, pre, count = 0; - private int[] id, low; - private boolean[] marked; - private boolean[][] adj; - private Stack stack = new Stack<>(); - - // Tarjan input requires an NxN adjacency matrix - public Tarjan(boolean[][] adj) { - n = adj.length; - this.adj = adj; - marked = new boolean[n]; - id = new int[n]; - low = new int[n]; - for (int u = 0; u < n; u++) if (!marked[u]) dfs(u); - } - - private void dfs(int u) { - marked[u] = true; - low[u] = pre++; - int min = low[u]; - stack.push(u); - for (int v = 0; v < n; v++) { - if (adj[u][v]) { - if (!marked[v]) dfs(v); - if (low[v] < min) min = low[v]; - } - } - if (min < low[u]) { - low[u] = min; - return; - } - int v; - do { - v = stack.pop(); - id[v] = count; - low[v] = n; - } while (v != u); - count++; - } - - // Returns the id array with the strongly connected components. - // If id[i] == id[j] then nodes i and j are part of the same strongly connected component. - public int[] getStronglyConnectedComponents() { - return id.clone(); - } - - // Returns the number of strongly connected components in this graph - public int countStronglyConnectedComponents() { - return count; - } - } -} diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanSccSolverAdjacencyList.java b/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanSccSolverAdjacencyList.java index 18f547b43..9e1a6bb0e 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanSccSolverAdjacencyList.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanSccSolverAdjacencyList.java @@ -1,5 +1,5 @@ /** - * An implementation of Tarjan's Strongly Connected Components algorithm using an adjacency list. + * Implementation of Tarjan's Strongly Connected Components algorithm using an adjacency list. * *

Verified against: * @@ -9,7 +9,9 @@ *

  • https://www.hackerearth.com/practice/algorithms/graphs/strongly-connected-components/tutorial * * - *

    Time complexity: O(V+E) + *

    Time: O(V + E) + * + *

    Space: O(V) * * @author William Fiset, william.alexandre.fiset@gmail.com */ @@ -21,51 +23,62 @@ public class TarjanSccSolverAdjacencyList { - private int n; - private List> graph; + private final int n; + private final List> graph; private boolean solved; private int sccCount, id; - private boolean[] visited; + private boolean[] onStack; private int[] ids, low, sccs; private Deque stack; private static final int UNVISITED = -1; + /** + * Creates a Tarjan SCC solver for the given directed graph. + * + * @param graph adjacency list representation of a directed graph. + * @throws IllegalArgumentException if the graph is null. + */ public TarjanSccSolverAdjacencyList(List> graph) { - if (graph == null) throw new IllegalArgumentException("Graph cannot be null."); + if (graph == null) + throw new IllegalArgumentException("Graph cannot be null."); n = graph.size(); this.graph = graph; } - // Returns the number of strongly connected components in the graph. + /** Returns the number of strongly connected components in the graph. */ public int sccCount() { - if (!solved) solve(); + if (!solved) + solve(); return sccCount; } - // Get the connected components of this graph. If two indexes - // have the same value then they're in the same SCC. + /** + * Returns the SCC id for each node. If two nodes have the same value, they belong to the same + * SCC. + */ public int[] getSccs() { - if (!solved) solve(); + if (!solved) + solve(); return sccs; } + /** Runs Tarjan's algorithm. */ public void solve() { - if (solved) return; + if (solved) + return; ids = new int[n]; low = new int[n]; sccs = new int[n]; - visited = new boolean[n]; + onStack = new boolean[n]; stack = new ArrayDeque<>(); Arrays.fill(ids, UNVISITED); - for (int i = 0; i < n; i++) { - if (ids[i] == UNVISITED) { + for (int i = 0; i < n; i++) + if (ids[i] == UNVISITED) dfs(i); - } - } solved = true; } @@ -73,59 +86,41 @@ public void solve() { private void dfs(int at) { ids[at] = low[at] = id++; stack.push(at); - visited[at] = true; + onStack[at] = true; for (int to : graph.get(at)) { - if (ids[to] == UNVISITED) { + if (ids[to] == UNVISITED) dfs(to); - } - if (visited[to]) { + if (onStack[to]) low[at] = min(low[at], low[to]); - } - /* - TODO(william): investigate whether the proper way to update the lowlinks - is the following bit of code. From my experience this doesn't seem to - matter if the output is placed in a separate output array, but this needs - further investigation. - - if (ids[to] == UNVISITED) { - dfs(to); - low[at] = min(low[at], low[to]); - } - if (visited[to]) { - low[at] = min(low[at], ids[to]); - } - */ - } - // On recursive callback, if we're at the root node (start of SCC) - // empty the seen stack until back to root. + // If we're at the root of an SCC, pop all nodes in this component off the stack. if (ids[at] == low[at]) { for (int node = stack.pop(); ; node = stack.pop()) { - visited[node] = false; + onStack[node] = false; sccs[node] = sccCount; - if (node == at) break; + if (node == at) + break; } sccCount++; } } - // Initializes adjacency list with n nodes. + /** Creates an adjacency list with n nodes. */ public static List> createGraph(int n) { List> graph = new ArrayList<>(n); - for (int i = 0; i < n; i++) graph.add(new ArrayList<>()); + for (int i = 0; i < n; i++) + graph.add(new ArrayList<>()); return graph; } - // Adds a directed edge from node 'from' to node 'to' + /** Adds a directed edge from node 'from' to node 'to'. */ public static void addEdge(List> graph, int from, int to) { graph.get(from).add(to); } - /* Example usage: */ - - public static void main(String[] arg) { + public static void main(String[] args) { int n = 8; List> graph = createGraph(n); @@ -148,15 +143,9 @@ public static void main(String[] arg) { int[] sccs = solver.getSccs(); Map> multimap = new HashMap<>(); for (int i = 0; i < n; i++) { - if (!multimap.containsKey(sccs[i])) multimap.put(sccs[i], new ArrayList<>()); - multimap.get(sccs[i]).add(i); + multimap.computeIfAbsent(sccs[i], k -> new ArrayList<>()).add(i); } - // Prints: - // Number of Strongly Connected Components: 3 - // Nodes: [0, 1, 2] form a Strongly Connected Component. - // Nodes: [3, 7] form a Strongly Connected Component. - // Nodes: [4, 5, 6] form a Strongly Connected Component. System.out.printf("Number of Strongly Connected Components: %d\n", solver.sccCount()); for (List scc : multimap.values()) { System.out.println("Nodes: " + scc + " form a Strongly Connected Component."); diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/TopologicalSortAdjacencyList.java b/src/main/java/com/williamfiset/algorithms/graphtheory/TopologicalSortAdjacencyList.java index 71d6233ad..cc9802056 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/TopologicalSortAdjacencyList.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/TopologicalSortAdjacencyList.java @@ -1,11 +1,16 @@ /** - * This topological sort implementation takes an adjacency list of an acyclic graph and returns an - * array with the indexes of the nodes in a (non unique) topological order which tells you how to - * process the nodes in the graph. More precisely from wiki: A topological ordering is a linear - * ordering of its vertices such that for every directed edge uv from vertex u to vertex v, u comes - * before v in the ordering. + * Topological sort implementation using DFS on an adjacency list of a Directed Acyclic Graph (DAG). + * Returns an array with the node indexes in a (non-unique) topological order: for every directed + * edge u -> v, u comes before v in the ordering. * - *

    Time Complexity: O(V + E) + *

    Also includes a method to find shortest paths in a DAG using the topological ordering. + * + *

    NOTE: An arguably simpler approach to topological sorting is Kahn's algorithm, which uses + * in-degree counting and BFS instead of DFS. See {@link Kahns}. + * + *

    Time: O(V + E) + * + *

    Space: O(V + E) * * @author William Fiset, william.alexandre.fiset@gmail.com */ @@ -15,95 +20,90 @@ public class TopologicalSortAdjacencyList { - // Helper Edge class to describe edges in the graph static class Edge { int from, to, weight; - public Edge(int f, int t, int w) { - from = f; - to = t; - weight = w; + public Edge(int from, int to, int weight) { + this.from = from; + this.to = to; + this.weight = weight; } } - // Helper method that performs a depth first search on the graph to give - // us the topological ordering we want. Instead of maintaining a stack - // of the nodes we see we simply place them inside the ordering array - // in reverse order for simplicity. - private static int dfs( - int i, int at, boolean[] visited, int[] ordering, Map> graph) { - - visited[at] = true; - - List edges = graph.get(at); - - if (edges != null) - for (Edge edge : edges) if (!visited[edge.to]) i = dfs(i, edge.to, visited, ordering, graph); - - ordering[i] = at; - return i - 1; - } - - // Finds a topological ordering of the nodes in a Directed Acyclic Graph (DAG) - // The input to this function is an adjacency list for a graph and the number - // of nodes in the graph. - // - // NOTE: 'numNodes' is not necessarily the number of nodes currently present - // in the adjacency list since you can have singleton nodes with no edges which - // wouldn't be present in the adjacency list but are still part of the graph! - // + /** + * Finds a topological ordering of the nodes in a DAG. + * + *

    NOTE: {@code numNodes} is not necessarily the number of nodes in the adjacency list since + * singleton nodes with no edges wouldn't be present but are still part of the graph. + * + * @param graph adjacency list mapping node index to outgoing edges. + * @param numNodes total number of nodes in the graph. + * @return array of node indexes in topological order. + */ public static int[] topologicalSort(Map> graph, int numNodes) { - int[] ordering = new int[numNodes]; boolean[] visited = new boolean[numNodes]; int i = numNodes - 1; for (int at = 0; at < numNodes; at++) - if (!visited[at]) i = dfs(i, at, visited, ordering, graph); + if (!visited[at]) + i = dfs(i, at, visited, ordering, graph); return ordering; } - // A useful application of the topological sort is to find the shortest path - // between two nodes in a Directed Acyclic Graph (DAG). Given an adjacency list - // this method finds the shortest path to all nodes starting at 'start' - // - // NOTE: 'numNodes' is not necessarily the number of nodes currently present - // in the adjacency list since you can have singleton nodes with no edges which - // wouldn't be present in the adjacency list but are still part of the graph! - // - public static Integer[] dagShortestPath(Map> graph, int start, int numNodes) { + // Places nodes into the ordering array in reverse DFS post-order. + private static int dfs( + int i, int at, boolean[] visited, int[] ordering, Map> graph) { + visited[at] = true; + + List edges = graph.get(at); + if (edges != null) + for (Edge edge : edges) + if (!visited[edge.to]) + i = dfs(i, edge.to, visited, ordering, graph); + + ordering[i] = at; + return i - 1; + } + /** + * Finds the shortest path from {@code start} to all other reachable nodes in a DAG. + * + *

    NOTE: {@code numNodes} is not necessarily the number of nodes in the adjacency list since + * singleton nodes with no edges wouldn't be present but are still part of the graph. + * + * @param graph adjacency list mapping node index to outgoing edges. + * @param start the source node. + * @param numNodes total number of nodes in the graph. + * @return array of shortest distances, null for unreachable nodes. + */ + public static Integer[] dagShortestPath( + Map> graph, int start, int numNodes) { int[] topsort = topologicalSort(graph, numNodes); Integer[] dist = new Integer[numNodes]; dist[start] = 0; for (int i = 0; i < numNodes; i++) { - int nodeIndex = topsort[i]; - if (dist[nodeIndex] != null) { - List adjacentEdges = graph.get(nodeIndex); - if (adjacentEdges != null) { - for (Edge edge : adjacentEdges) { - - int newDist = dist[nodeIndex] + edge.weight; - if (dist[edge.to] == null) dist[edge.to] = newDist; - else dist[edge.to] = Math.min(dist[edge.to], newDist); - } - } + if (dist[nodeIndex] == null) + continue; + for (Edge edge : graph.getOrDefault(nodeIndex, Collections.emptyList())) { + int newDist = dist[nodeIndex] + edge.weight; + if (dist[edge.to] == null || newDist < dist[edge.to]) + dist[edge.to] = newDist; } } return dist; } - // Example usage of topological sort public static void main(String[] args) { - - // Graph setup final int N = 7; Map> graph = new HashMap<>(); - for (int i = 0; i < N; i++) graph.put(i, new ArrayList<>()); + for (int i = 0; i < N; i++) + graph.put(i, new ArrayList<>()); + graph.get(0).add(new Edge(0, 1, 3)); graph.get(0).add(new Edge(0, 2, 2)); graph.get(0).add(new Edge(0, 5, 3)); @@ -115,18 +115,10 @@ public static void main(String[] args) { graph.get(5).add(new Edge(5, 4, 7)); int[] ordering = topologicalSort(graph, N); + System.out.println(Arrays.toString(ordering)); - // // Prints: [6, 0, 5, 1, 2, 3, 4] - System.out.println(java.util.Arrays.toString(ordering)); - - // Finds all the shortest paths starting at node 0 Integer[] dists = dagShortestPath(graph, 0, N); - - // Find the shortest path from 0 to 4 which is 8.0 - System.out.println(dists[4]); - - // Find the shortest path from 0 to 6 which - // is null since 6 is not reachable! - System.out.println(dists[6]); + System.out.println(dists[4]); // 8 + System.out.println(dists[6]); // null (unreachable) } }