diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/DialsAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/DialsAlgorithm.java
new file mode 100644
index 000000000000..da3fba88c618
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/DialsAlgorithm.java
@@ -0,0 +1,114 @@
+package com.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An implementation of Dial's Algorithm for the single-source shortest path problem.
+ * This algorithm is an optimization of Dijkstra's algorithm and is particularly
+ * efficient for graphs with small, non-negative integer edge weights.
+ *
+ * It uses a bucket queue (implemented here as a List of HashSets) to store vertices,
+ * where each bucket corresponds to a specific distance from the source. This is more
+ * efficient than a standard priority queue when the range of edge weights is small.
+ *
+ * Time Complexity: O(E + W * V), where E is the number of edges, V is the number
+ * of vertices, and W is the maximum weight of any edge.
+ *
+ * @see Wikipedia - Dial's Algorithm
+ */
+public final class DialsAlgorithm {
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private DialsAlgorithm() {
+ }
+ /**
+ * Represents an edge in the graph, connecting to a destination vertex with a given weight.
+ */
+ public static 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;
+ }
+ }
+ /**
+ * Finds the shortest paths from a source vertex to all other vertices in a weighted graph.
+ *
+ * @param graph The graph represented as an adjacency list.
+ * @param source The source vertex to start from (0-indexed).
+ * @param maxEdgeWeight The maximum weight of any single edge in the graph.
+ * @return An array of integers where the value at each index `i` is the
+ * shortest distance from the source to vertex `i`. Unreachable vertices
+ * will have a value of Integer.MAX_VALUE.
+ * @throws IllegalArgumentException if the source vertex is out of bounds.
+ */
+ public static int[] run(List> graph, int source, int maxEdgeWeight) {
+ int numVertices = graph.size();
+ if (source < 0 || source >= numVertices) {
+ throw new IllegalArgumentException("Source vertex is out of bounds.");
+ }
+
+ // Initialize distances array
+ int[] distances = new int[numVertices];
+ Arrays.fill(distances, Integer.MAX_VALUE);
+ distances[source] = 0;
+
+ // The bucket queue. Size is determined by the max possible path length.
+ int maxPathWeight = maxEdgeWeight * (numVertices > 0 ? numVertices - 1 : 0);
+ List> buckets = new ArrayList<>(maxPathWeight + 1);
+ for (int i = 0; i <= maxPathWeight; i++) {
+ buckets.add(new HashSet<>());
+ }
+
+ // Add the source vertex to the first bucket
+ buckets.get(0).add(source);
+
+ // Process buckets in increasing order of distance
+ for (int d = 0; d <= maxPathWeight; d++) {
+ // Process all vertices in the current bucket
+ while (!buckets.get(d).isEmpty()) {
+ // Get and remove a vertex from the current bucket
+ int u = buckets.get(d).iterator().next();
+ buckets.get(d).remove(u);
+
+ // If we've found a shorter path already, skip
+ if (d > distances[u]) {
+ continue;
+ }
+
+ // Relax all adjacent edges
+ for (Edge edge : graph.get(u)) {
+ int v = edge.getDestination();
+ int weight = edge.getWeight();
+
+ // If a shorter path to v is found
+ if (distances[u] != Integer.MAX_VALUE && distances[u] + weight < distances[v]) {
+ // If v was already in a bucket, remove it from the old one
+ if (distances[v] != Integer.MAX_VALUE) {
+ buckets.get(distances[v]).remove(v);
+ }
+ // Update distance and move v to the new bucket
+ distances[v] = distances[u] + weight;
+ buckets.get(distances[v]).add(v);
+ }
+ }
+ }
+ }
+ return distances;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/DialsAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/DialsAlgorithmTest.java
new file mode 100644
index 000000000000..2350455d4329
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/DialsAlgorithmTest.java
@@ -0,0 +1,88 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+final class DialsAlgorithmTest {
+
+ private List> graph;
+ private static final int NUM_VERTICES = 6;
+ private static final int MAX_EDGE_WEIGHT = 10;
+
+ @BeforeEach
+ void setUp() {
+ graph = new ArrayList<>();
+ for (int i = 0; i < NUM_VERTICES; i++) {
+ graph.add(new ArrayList<>());
+ }
+ }
+
+ private void addEdge(int u, int v, int weight) {
+ graph.get(u).add(new DialsAlgorithm.Edge(v, weight));
+ }
+
+ @Test
+ @DisplayName("Test with a simple connected graph")
+ void testSimpleGraph() {
+ // Build graph from a standard example
+ addEdge(0, 1, 2);
+ addEdge(0, 2, 4);
+ addEdge(1, 2, 1);
+ addEdge(1, 3, 7);
+ addEdge(2, 4, 3);
+ addEdge(3, 5, 1);
+ addEdge(4, 3, 2);
+ addEdge(4, 5, 5);
+
+ int[] expectedDistances = {0, 2, 3, 8, 6, 9};
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test with a disconnected node")
+ void testDisconnectedNode() {
+ addEdge(0, 1, 5);
+ addEdge(1, 2, 5);
+ // Node 3, 4, 5 are disconnected
+
+ int[] expectedDistances = {0, 5, 10, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test with source as destination")
+ void testSourceIsDestination() {
+ addEdge(0, 1, 10);
+ int[] expectedDistances = {0, 10, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
+ // Run with source 0
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test graph with multiple paths to a node")
+ void testMultiplePaths() {
+ addEdge(0, 1, 10);
+ addEdge(0, 2, 3);
+ addEdge(2, 1, 2); // Shorter path to 1 is via 2 (3+2=5)
+
+ int[] expectedDistances = {0, 5, 3, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
+ int[] actualDistances = DialsAlgorithm.run(graph, 0, MAX_EDGE_WEIGHT);
+ assertArrayEquals(expectedDistances, actualDistances);
+ }
+
+ @Test
+ @DisplayName("Test with an invalid source vertex")
+ void testInvalidSource() {
+ assertThrows(IllegalArgumentException.class, () -> DialsAlgorithm.run(graph, -1, MAX_EDGE_WEIGHT));
+ assertThrows(IllegalArgumentException.class, () -> DialsAlgorithm.run(graph, NUM_VERTICES, MAX_EDGE_WEIGHT));
+ }
+}