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