1+ package com .thealgorithms .datastructures .graphs ;
2+
3+ import java .util .ArrayList ;
4+ import java .util .Arrays ;
5+ import java .util .HashSet ;
6+ import java .util .List ;
7+ import java .util .Set ;
8+
9+ /**
10+ * An implementation of Dial's Algorithm for the single-source shortest path problem.
11+ * This algorithm is an optimization of Dijkstra's algorithm and is particularly
12+ * efficient for graphs with small, non-negative integer edge weights.
13+ *
14+ * It uses a bucket queue (implemented here as a List of HashSets) to store vertices,
15+ * where each bucket corresponds to a specific distance from the source. This is more
16+ * efficient than a standard priority queue when the range of edge weights is small.
17+ *
18+ * Time Complexity: O(E + W * V), where E is the number of edges, V is the number
19+ * of vertices, and W is the maximum weight of any edge.
20+ *
21+ * @see <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm#Dial's_algorithm">Wikipedia - Dial's Algorithm</a>
22+ */
23+ public final class DialsAlgorithm {
24+
25+ /**
26+ * Private constructor to prevent instantiation of this utility class.
27+ */
28+ private DialsAlgorithm () {
29+ }
30+
31+ /**
32+ * Represents an edge in the graph, connecting to a destination vertex with a given weight.
33+ */
34+ public static class Edge {
35+ private final int destination ;
36+ private final int weight ;
37+
38+ public Edge (int destination , int weight ) {
39+ this .destination = destination ;
40+ this .weight = weight ;
41+ }
42+
43+ public int getDestination () {
44+ return destination ;
45+ }
46+
47+ public int getWeight () {
48+ return weight ;
49+ }
50+ }
51+
52+ /**
53+ * Finds the shortest paths from a source vertex to all other vertices in a weighted graph.
54+ *
55+ * @param graph The graph represented as an adjacency list.
56+ * @param source The source vertex to start from (0-indexed).
57+ * @param maxEdgeWeight The maximum weight of any single edge in the graph.
58+ * @return An array of integers where the value at each index `i` is the
59+ * shortest distance from the source to vertex `i`. Unreachable vertices
60+ * will have a value of Integer.MAX_VALUE.
61+ * @throws IllegalArgumentException if the source vertex is out of bounds.
62+ */
63+ public static int [] run (List <List <Edge >> graph , int source , int maxEdgeWeight ) {
64+ int numVertices = graph .size ();
65+ if (source < 0 || source >= numVertices ) {
66+ throw new IllegalArgumentException ("Source vertex is out of bounds." );
67+ }
68+
69+ // Initialize distances array
70+ int [] distances = new int [numVertices ];
71+ Arrays .fill (distances , Integer .MAX_VALUE );
72+ distances [source ] = 0 ;
73+
74+ // The bucket queue. Size is determined by the max possible path length.
75+ int maxPathWeight = maxEdgeWeight * (numVertices > 0 ? numVertices - 1 : 0 );
76+ List <Set <Integer >> buckets = new ArrayList <>(maxPathWeight + 1 );
77+ for (int i = 0 ; i <= maxPathWeight ; i ++) {
78+ buckets .add (new HashSet <>());
79+ }
80+
81+ // Add the source vertex to the first bucket
82+ buckets .get (0 ).add (source );
83+
84+ // Process buckets in increasing order of distance
85+ for (int d = 0 ; d <= maxPathWeight ; d ++) {
86+ // Process all vertices in the current bucket
87+ while (!buckets .get (d ).isEmpty ()) {
88+ // Get and remove a vertex from the current bucket
89+ int u = buckets .get (d ).iterator ().next ();
90+ buckets .get (d ).remove (u );
91+
92+ // If we've found a shorter path already, skip
93+ if (d > distances [u ]) {
94+ continue ;
95+ }
96+
97+ // Relax all adjacent edges
98+ for (Edge edge : graph .get (u )) {
99+ int v = edge .getDestination ();
100+ int weight = edge .getWeight ();
101+
102+ // If a shorter path to v is found
103+ if (distances [u ] != Integer .MAX_VALUE && distances [u ] + weight < distances [v ]) {
104+ // If v was already in a bucket, remove it from the old one
105+ if (distances [v ] != Integer .MAX_VALUE ) {
106+ buckets .get (distances [v ]).remove (v );
107+ }
108+ // Update distance and move v to the new bucket
109+ distances [v ] = distances [u ] + weight ;
110+ buckets .get (distances [v ]).add (v );
111+ }
112+ }
113+ }
114+ }
115+ return distances ;
116+ }
117+ }
0 commit comments