Skip to content

Commit 84ab05b

Browse files
author
SUZUB
committed
others: use PriorityQueue in Dijkstra; add negative-weight test
1 parent b76962d commit 84ab05b

File tree

2 files changed

+68
-21
lines changed

2 files changed

+68
-21
lines changed

src/main/java/com/thealgorithms/others/Dijkstra.java

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import java.util.HashMap;
44
import java.util.Map;
5-
import java.util.NavigableSet;
6-
import java.util.TreeSet;
5+
import java.util.PriorityQueue;
6+
import java.util.Comparator;
77
/**
88
* Dijkstra's algorithm,is a graph search algorithm that solves the
99
* single-source shortest path problem for a graph with nonnegative edge path
@@ -12,7 +12,10 @@
1212
* <p>
1313
* NOTE: The inputs to Dijkstra's algorithm are a directed and weighted graph
1414
* consisting of 2 or more nodes, generally represented by an adjacency matrix
15-
* or list, and a start node.
15+
* or list, and a start node. This implementation uses a binary heap
16+
* (Java's {@link PriorityQueue}) to achieve a time complexity of
17+
* O((V + E) log V) in practice. Practical use-cases include GPS routing and
18+
* network routing where all edge weights are non-negative.
1619
*
1720
* <p>
1821
* Original source of code:
@@ -182,46 +185,72 @@ public void dijkstra(String startName) {
182185
return;
183186
}
184187
final Vertex source = graph.get(startName);
185-
NavigableSet<Vertex> q = new TreeSet<>();
186188

187-
// set-up vertices
189+
// initialize distances
188190
for (Vertex v : graph.values()) {
189191
v.previous = v == source ? source : null;
190192
v.dist = v == source ? 0 : Integer.MAX_VALUE;
191-
q.add(v);
192193
}
193194

194-
dijkstra(q);
195-
}
195+
// Priority queue of (vertex, knownDist) entries. We push new entries when
196+
// a shorter distance is found; stale entries are ignored when polled.
197+
PriorityQueue<NodeEntry> pq = new PriorityQueue<>(Comparator
198+
.comparingInt((NodeEntry e) -> e.dist)
199+
.thenComparing(e -> e.vertex.name));
200+
201+
pq.add(new NodeEntry(source, 0));
196202

203+
dijkstra(pq);
204+
}
197205
/**
198-
* Implementation of dijkstra's algorithm using a binary heap.
206+
* Implementation of dijkstra's algorithm using a priority queue of entries.
199207
*/
200-
private void dijkstra(final NavigableSet<Vertex> q) {
201-
Vertex u;
202-
Vertex v;
203-
while (!q.isEmpty()) {
204-
// vertex with shortest distance (first iteration will return source)
205-
u = q.pollFirst();
208+
private void dijkstra(final PriorityQueue<NodeEntry> pq) {
209+
while (!pq.isEmpty()) {
210+
final NodeEntry entry = pq.poll();
211+
final Vertex u = entry.vertex;
212+
213+
// ignore stale/popped entries
214+
if (entry.dist != u.dist) {
215+
continue;
216+
}
217+
206218
if (u.dist == Integer.MAX_VALUE) {
207-
break; // we can ignore u (and any other remaining vertices) since they are
208-
// unreachable
219+
break; // remaining vertices are unreachable
209220
}
221+
210222
// look at distances to each neighbour
211223
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
212-
v = a.getKey(); // the neighbour in this iteration
224+
final Vertex v = a.getKey(); // the neighbour in this iteration
225+
final int weight = a.getValue();
226+
227+
if (weight < 0) {
228+
throw new IllegalArgumentException("Graph contains negative edge weight: " + weight);
229+
}
213230

214-
final int alternateDist = u.dist + a.getValue();
231+
final int alternateDist = u.dist + weight;
215232
if (alternateDist < v.dist) { // shorter path to neighbour found
216-
q.remove(v);
217233
v.dist = alternateDist;
218234
v.previous = u;
219-
q.add(v);
235+
pq.add(new NodeEntry(v, alternateDist));
220236
}
221237
}
222238
}
223239
}
224240

241+
/**
242+
* Helper entry for the priority queue to avoid costly removals (no decrease-key).
243+
*/
244+
private static class NodeEntry {
245+
final Vertex vertex;
246+
final int dist;
247+
248+
NodeEntry(Vertex vertex, int dist) {
249+
this.vertex = vertex;
250+
this.dist = dist;
251+
}
252+
}
253+
225254
/**
226255
* Prints a path from the source to the specified vertex
227256
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.thealgorithms.others;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
/**
8+
* Unit tests for Dijkstra negative-weight detection.
9+
*/
10+
public class DijkstraTest {
11+
12+
@Test
13+
void testNegativeWeightThrows() {
14+
Graph.Edge[] edges = { new Graph.Edge("a", "b", -1) };
15+
Graph g = new Graph(edges);
16+
assertThrows(IllegalArgumentException.class, () -> g.dijkstra("a"));
17+
}
18+
}

0 commit comments

Comments
 (0)