diff --git a/src/main/java/com/thealgorithms/backtracking/DijkstraAlgorithm.java b/src/main/java/com/thealgorithms/backtracking/DijkstraAlgorithm.java new file mode 100644 index 000000000000..df5eea8e1788 --- /dev/null +++ b/src/main/java/com/thealgorithms/backtracking/DijkstraAlgorithm.java @@ -0,0 +1,127 @@ +package com.thealgorithms.backtracking; + +// Problem Statement: Find the shortest path from a starting node to all other nodes in a weighted graph. + +// Example: +// 7 +// A -------- B +// | | +// 3| |2 +// | | +// C -------- D +// 1 +// Starting Node: A +// Result: +// Shortest paths: + +// A -> A: 0 +// A -> B: 7 +// A -> C: 3 +// A -> D: 4 (A -> C -> D) + +import java.util.*; + +// Class representing an Edge in the graph +class Edge { + private final int destination; + private final int weight; + + public Edge(int destination, int weight) { + this.destination = destination; + this.weight = weight; + } + + public int getDestination() { + return destination; + } + + public int getWeight() { + return weight; + } +} + +// Class representing a Graph +class Graph { + private final Map> adjList; + + public Graph() { + this.adjList = new HashMap<>(); + } + + // Add edge between two nodes with a given weight + public void addEdge(int source, int destination, int weight) { + adjList.computeIfAbsent(source, k -> new ArrayList<>()).add(new Edge(destination, weight)); + adjList.computeIfAbsent(destination, k -> new ArrayList<>()).add(new Edge(source, weight)); // undirected graph + } + + public List getEdges(int node) { + return adjList.getOrDefault(node, new ArrayList<>()); + } + + public Set getAllNodes() { + return adjList.keySet(); + } +} + +// Class representing a Node (for use in the PriorityQueue) +class Node { + private final int node; + private final int distance; + + public Node(int node, int distance) { + this.node = node; + this.distance = distance; + } + + public int getNode() { + return node; + } + + public int getDistance() { + return distance; + } +} + +// Dijkstra's Algorithm class +public class Dijkstra { + + // method to find shortest paths from a given start node + public Map findShortestPaths(Graph graph, int startNode) { + // priority Queue to select the minimum distance node + PriorityQueue pq = new PriorityQueue<>(Comparator.comparingInt(Node::getDistance)); + Map distances = new HashMap<>(); + Map visited = new HashMap<>(); + + // Initialize distances with infinity + for (int node : graph.getAllNodes()) { + distances.put(node, Integer.MAX_VALUE); + visited.put(node, false); + } + + // Starting point + distances.put(startNode, 0); + pq.add(new Node(startNode, 0)); + + while (!pq.isEmpty()) { + Node currentNode = pq.poll(); + int current = currentNode.getNode(); + + if (visited.get(current)) { + continue; + } + visited.put(current, true); + + // Update the distances to the neighboring nodes + for (Edge edge : graph.getEdges(current)) { + int neighbor = edge.getDestination(); + int newDist = distances.get(current) + edge.getWeight(); + + if (newDist < distances.get(neighbor)) { + distances.put(neighbor, newDist); + pq.add(new Node(neighbor, newDist)); + } + } + } + return distances; + } +} diff --git a/src/test/java/com/thealgorithms/backtracking/DijkstraAlgorithmTest.java b/src/test/java/com/thealgorithms/backtracking/DijkstraAlgorithmTest.java new file mode 100644 index 000000000000..e2180758a6f9 --- /dev/null +++ b/src/test/java/com/thealgorithms/backtracking/DijkstraAlgorithmTest.java @@ -0,0 +1,85 @@ +package com.thealgorithms.backtracking; + + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import java.util.*; + +class DijkstraTest { + + @Test + void testSingleNodeGraph() { + Graph graph = new Graph(); + graph.addEdge(1, 1, 0); + + Dijkstra dijkstra = new Dijkstra(); + Map distances = dijkstra.findShortestPaths(graph, 1); + + assertEquals(0, (int) distances.get(1)); + } + + @Test + void testSimpleGraph() { + Graph graph = new Graph(); + graph.addEdge(1, 2, 1); + graph.addEdge(2, 3, 2); + graph.addEdge(1, 3, 4); + + Dijkstra dijkstra = new Dijkstra(); + Map distances = dijkstra.findShortestPaths(graph, 1); + + assertEquals(0, (int) distances.get(1)); + assertEquals(1, (int) distances.get(2)); + assertEquals(3, (int) distances.get(3)); + } + + @Test + void testComplexGraph() { + Graph graph = new Graph(); + graph.addEdge(1, 2, 10); + graph.addEdge(1, 3, 5); + graph.addEdge(3, 2, 3); + graph.addEdge(2, 4, 1); + graph.addEdge(3, 4, 9); + graph.addEdge(4, 5, 2); + + Dijkstra dijkstra = new Dijkstra(); + Map distances = dijkstra.findShortestPaths(graph, 1); + + assertEquals(0, (int) distances.get(1)); + assertEquals(8, (int) distances.get(2)); + assertEquals(5, (int) distances.get(3)); + assertEquals(9, (int) distances.get(4)); + assertEquals(11, (int) distances.get(5)); + } + + @Test + void testDisconnectedGraph() { + Graph graph = new Graph(); + graph.addEdge(1, 2, 5); + graph.addEdge(3, 4, 7); + + Dijkstra dijkstra = new Dijkstra(); + Map distances = dijkstra.findShortestPaths(graph, 1); + + assertEquals(0, (int) distances.get(1)); + assertEquals(5, (int) distances.get(2)); + assertNull(distances.get(3)); + } + + @Test + void testGraphWithLoops() { + Graph graph = new Graph(); + graph.addEdge(1, 1, 0); + graph.addEdge(1, 2, 2); + graph.addEdge(2, 3, 4); + graph.addEdge(3, 1, 6); + + Dijkstra dijkstra = new Dijkstra(); + Map distances = dijkstra.findShortestPaths(graph, 1); + + assertEquals(0, (int) distances.get(1)); + assertEquals(2, (int) distances.get(2)); + assertEquals(6, (int) distances.get(3)); + } +}