diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 000000000000..8671558cf098 --- /dev/null +++ b/desktop.ini @@ -0,0 +1,2 @@ +[.ShellClassInfo] +LocalizedResourceName=@dijkstra-priority-queue,0 diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java index a4cc2ffdd4a6..1002b2fb87e0 100644 --- a/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java +++ b/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java @@ -166,7 +166,6 @@ public void merge(ORSet other) { */ public static class Pair { private final T element; - private final String uniqueTag; /** * Constructs a pair with the specified element and unique tag. @@ -176,7 +175,6 @@ public static class Pair { */ public Pair(T element, String uniqueTag) { this.element = element; - this.uniqueTag = uniqueTag; } /** diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java index 72a12cd58401..422e8953625f 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java @@ -10,7 +10,6 @@ * * @param the type of elements held in this list */ -@SuppressWarnings("rawtypes") public class CircleLinkedList { /** diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java b/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java index 0b4fcd91483c..a96d7dcd959b 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java @@ -227,7 +227,6 @@ private static class Node { private final List> forward; private final List> backward; - @SuppressWarnings("unchecked") Node(E value, int height) { this.value = value; this.height = height; diff --git a/src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java b/src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java index 9369b3fc9a64..69bdedda9ac5 100644 --- a/src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java +++ b/src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java @@ -22,7 +22,6 @@ public class StackArray implements Stack { /** * Creates a stack with a default capacity. */ - @SuppressWarnings("unchecked") public StackArray() { this(DEFAULT_CAPACITY); } diff --git a/src/main/java/com/thealgorithms/graphs/DijkstraPriorityQueue.java b/src/main/java/com/thealgorithms/graphs/DijkstraPriorityQueue.java new file mode 100644 index 000000000000..0d48894adc42 --- /dev/null +++ b/src/main/java/com/thealgorithms/graphs/DijkstraPriorityQueue.java @@ -0,0 +1,93 @@ +package com.thealgorithms.graphs; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; + +/** + * Dijkstra's algorithm finds the shortest path from a source vertex to all other vertices + * in a weighted graph. This implementation uses a PriorityQueue for optimal performance. + * + * Applications: GPS routing (Google Maps), Network routing (OSPF protocol). + * + * Time Complexity: O((V + E) log V) + * Space Complexity: O(V) + */ +public class DijkstraPriorityQueue { + + public static class Edge { + int target; + int weight; + + public Edge(int target, int weight) { + this.target = target; + this.weight = weight; + } + } + + /** + * Finds the shortest paths from the source to all other vertices. + * + * @param source the starting vertex + * @param graph the adjacency list representation of the graph + * @param numVertices total number of vertices in the graph + * @return an array of shortest distances from source + * @throws IllegalArgumentException if any edge weight is negative or input is invalid + */ + public int[] runDijkstra(int source, Map> graph, int numVertices) { + // Validation for number of vertices + if (numVertices <= 0) { + return new int[0]; + } + + // Validation for null graph or invalid source index + if (graph == null || source < 0 || source >= numVertices) { + int[] emptyDist = new int[numVertices]; + Arrays.fill(emptyDist, Integer.MAX_VALUE); + if (source >= 0 && source < numVertices) { + emptyDist[source] = 0; + } + return emptyDist; + } + + // Min-priority queue based on distance (int[1]) + PriorityQueue pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1])); + int[] dist = new int[numVertices]; + Arrays.fill(dist, Integer.MAX_VALUE); + + dist[source] = 0; + pq.add(new int[] {source, 0}); + + while (!pq.isEmpty()) { + int[] current = pq.poll(); + int u = current[0]; + int d = current[1]; + + // If current distance is already greater than stored distance, skip + // This is a common "Partial" coverage point if not tested with multiple paths + if (d > dist[u]) { + continue; + } + + List neighbors = graph.get(u); + if (neighbors == null) { + continue; + } + + for (Edge edge : neighbors) { + // Dijkstra's algorithm does not support negative weights + if (edge.weight < 0) { + throw new IllegalArgumentException("Graph contains negative weight edge: " + edge.weight); + } + + if (dist[u] != Integer.MAX_VALUE && dist[u] + edge.weight < dist[edge.target]) { + dist[edge.target] = dist[u] + edge.weight; + pq.add(new int[] {edge.target, dist[edge.target]}); + } + } + } + return dist; + } +} diff --git a/src/main/java/com/thealgorithms/others/Dijkstra.java b/src/main/java/com/thealgorithms/others/Dijkstra.java index a379100a2f3b..170f051a4397 100644 --- a/src/main/java/com/thealgorithms/others/Dijkstra.java +++ b/src/main/java/com/thealgorithms/others/Dijkstra.java @@ -1,9 +1,10 @@ package com.thealgorithms.others; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; -import java.util.NavigableSet; -import java.util.TreeSet; +import java.util.PriorityQueue; + /** * Dijkstra's algorithm,is a graph search algorithm that solves the * single-source shortest path problem for a graph with nonnegative edge path @@ -12,7 +13,10 @@ *

* NOTE: The inputs to Dijkstra's algorithm are a directed and weighted graph * consisting of 2 or more nodes, generally represented by an adjacency matrix - * or list, and a start node. + * or list, and a start node. This implementation uses a binary heap + * (Java's {@link PriorityQueue}) to achieve a time complexity of + * O((V + E) log V) in practice. Practical use-cases include GPS routing and + * network routing where all edge weights are non-negative. * *

* Original source of code: @@ -182,46 +186,72 @@ public void dijkstra(String startName) { return; } final Vertex source = graph.get(startName); - NavigableSet q = new TreeSet<>(); - // set-up vertices + // initialize distances for (Vertex v : graph.values()) { v.previous = v == source ? source : null; v.dist = v == source ? 0 : Integer.MAX_VALUE; - q.add(v); } - dijkstra(q); - } + // Priority queue of (vertex, knownDist) entries. We push new entries when + // a shorter distance is found; stale entries are ignored when polled. + PriorityQueue pq = new PriorityQueue<>(Comparator + .comparingInt((NodeEntry e) -> e.dist) + .thenComparing(e -> e.vertex.name)); + + pq.add(new NodeEntry(source, 0)); + dijkstra(pq); + } /** - * Implementation of dijkstra's algorithm using a binary heap. + * Implementation of dijkstra's algorithm using a priority queue of entries. */ - private void dijkstra(final NavigableSet q) { - Vertex u; - Vertex v; - while (!q.isEmpty()) { - // vertex with shortest distance (first iteration will return source) - u = q.pollFirst(); + private void dijkstra(final PriorityQueue pq) { + while (!pq.isEmpty()) { + final NodeEntry entry = pq.poll(); + final Vertex u = entry.vertex; + + // ignore stale/popped entries + if (entry.dist != u.dist) { + continue; + } + if (u.dist == Integer.MAX_VALUE) { - break; // we can ignore u (and any other remaining vertices) since they are - // unreachable + break; // remaining vertices are unreachable } + // look at distances to each neighbour for (Map.Entry a : u.neighbours.entrySet()) { - v = a.getKey(); // the neighbour in this iteration + final Vertex v = a.getKey(); // the neighbour in this iteration + final int weight = a.getValue(); - final int alternateDist = u.dist + a.getValue(); + if (weight < 0) { + throw new IllegalArgumentException("Graph contains negative edge weight: " + weight); + } + + final int alternateDist = u.dist + weight; if (alternateDist < v.dist) { // shorter path to neighbour found - q.remove(v); v.dist = alternateDist; v.previous = u; - q.add(v); + pq.add(new NodeEntry(v, alternateDist)); } } } } + /** + * Helper entry for the priority queue to avoid costly removals (no decrease-key). + */ + private static class NodeEntry { + final Vertex vertex; + final int dist; + + NodeEntry(Vertex vertex, int dist) { + this.vertex = vertex; + this.dist = dist; + } + } + /** * Prints a path from the source to the specified vertex */ diff --git a/src/main/java/com/thealgorithms/physics/DampedOscillator.java b/src/main/java/com/thealgorithms/physics/DampedOscillator.java index 84028b628e77..f915dee6b9e5 100644 --- a/src/main/java/com/thealgorithms/physics/DampedOscillator.java +++ b/src/main/java/com/thealgorithms/physics/DampedOscillator.java @@ -34,10 +34,6 @@ public final class DampedOscillator { /** Damping coefficient (s⁻¹). */ private final double gamma; - private DampedOscillator() { - throw new AssertionError("No instances."); - } - /** * Constructs a damped oscillator model. * diff --git a/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java b/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java index 6de69c103b5a..38e98697b85a 100644 --- a/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java +++ b/src/main/java/com/thealgorithms/physics/SimplePendulumRK4.java @@ -8,10 +8,6 @@ */ public final class SimplePendulumRK4 { - private SimplePendulumRK4() { - throw new AssertionError("No instances."); - } - private final double length; // meters private final double g; // acceleration due to gravity (m/s^2) diff --git a/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java b/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java index 5ba79cdbb73a..4717c075da49 100644 --- a/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java @@ -10,8 +10,6 @@ * This scheduling algorithm is ideal for real-time systems where meeting deadlines is critical. */ public final class EDFScheduling { - private EDFScheduling() { - } private List processes; diff --git a/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java b/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java index 8ed689698557..a1b186c5c1c9 100644 --- a/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java @@ -30,14 +30,12 @@ private HighestResponseRatioNextScheduling() { * Represents a process in the scheduling algorithm. */ private static class Process { - String name; int arrivalTime; int burstTime; int turnAroundTime; boolean finished; Process(String name, int arrivalTime, int burstTime) { - this.name = name; this.arrivalTime = arrivalTime; this.burstTime = burstTime; this.turnAroundTime = 0; diff --git a/src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java b/src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java index cea0c793d340..c3f8f368b3b1 100644 --- a/src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java @@ -11,8 +11,6 @@ * Processes with more tickets have a higher chance of being selected. */ public final class LotteryScheduling { - private LotteryScheduling() { - } private List processes; private Random random; diff --git a/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java b/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java index 495e2e41bc5b..28d7d92a8be3 100644 --- a/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java +++ b/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java @@ -19,11 +19,11 @@ public class PerfectBinarySearch implements SearchAlgorithm { /** * @param array is an array where the element should be found * @param key is an element which should be found - * @param is any comparable type + * @param is any comparable type * @return index of the element */ @Override - public > int find(T[] array, T key) { + public > int find(U[] array, U key) { return search(array, key, 0, array.length - 1); } diff --git a/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java b/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java index 09ea349875ac..03438bcc130e 100644 --- a/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java +++ b/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java @@ -1,7 +1,6 @@ package com.thealgorithms.sorts; public class AdaptiveMergeSort implements SortAlgorithm { - @SuppressWarnings("unchecked") public > T[] sort(T[] array) { if (array.length <= 1) { return array; diff --git a/src/main/java/com/thealgorithms/sorts/SpreadSort.java b/src/main/java/com/thealgorithms/sorts/SpreadSort.java index 1401f3d454a8..22f4baa6c846 100644 --- a/src/main/java/com/thealgorithms/sorts/SpreadSort.java +++ b/src/main/java/com/thealgorithms/sorts/SpreadSort.java @@ -266,7 +266,6 @@ int size() { * * @return an array containing all elements in the bucket */ - @SuppressWarnings("unchecked") T[] toArray() { return Arrays.copyOf(elements, size); } diff --git a/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java b/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java index 8212793dfb79..db928f737877 100644 --- a/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java +++ b/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java @@ -99,7 +99,7 @@ void testIterator() { void testIteratorEmptyBag() { Bag bag = new Bag<>(); int count = 0; - for (String ignored : bag) { + for (String item : bag) { org.junit.jupiter.api.Assertions.fail("Iterator should not return any items for an empty bag"); } assertEquals(0, count, "Iterator should not traverse any items in an empty bag"); diff --git a/src/test/java/com/thealgorithms/graphs/DijkstraPriorityQueueTest.java b/src/test/java/com/thealgorithms/graphs/DijkstraPriorityQueueTest.java new file mode 100644 index 000000000000..9cc73fab4afc --- /dev/null +++ b/src/test/java/com/thealgorithms/graphs/DijkstraPriorityQueueTest.java @@ -0,0 +1,103 @@ +package com.thealgorithms.graphs; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link DijkstraPriorityQueue}. + */ +public class DijkstraPriorityQueueTest { + + private DijkstraPriorityQueue dijkstra; + + @BeforeEach + void setUp() { + dijkstra = new DijkstraPriorityQueue(); + } + + @Test + void testSimpleGraph() { + Map> graph = new HashMap<>(); + graph.put( + 0, + List.of( + new DijkstraPriorityQueue.Edge(1, 7), new DijkstraPriorityQueue.Edge(2, 9))); + graph.put(1, List.of(new DijkstraPriorityQueue.Edge(2, 10))); + graph.put(2, new ArrayList<>()); + + int[] result = dijkstra.runDijkstra(0, graph, 3); + int[] expected = {0, 7, 9}; + assertArrayEquals(expected, result); + } + + @Test + void testShorterPathFoundLater() { + // This ensures the 'if (dist[u] + edge.weight < dist[edge.target])' logic + // is fully tested + Map> graph = new HashMap<>(); + graph.put( + 0, + List.of( + new DijkstraPriorityQueue.Edge(1, 10), + new DijkstraPriorityQueue.Edge(2, 2))); + graph.put( + 2, + List.of( + new DijkstraPriorityQueue.Edge(1, 3))); // Path 0->2->1 is shorter (5) + // than 0->1 (10) + + int[] result = dijkstra.runDijkstra(0, graph, 3); + int[] expected = {0, 5, 2}; + assertArrayEquals(expected, result); + } + + @Test + void testStalePriorityQueueEntry() { + // This forces 'if (d > dist[u]) continue;' to execute + Map> graph = new HashMap<>(); + // Two edges to the same target: the PQ will have two entries for node 1 + graph.put( + 0, + List.of( + new DijkstraPriorityQueue.Edge(1, 10), new DijkstraPriorityQueue.Edge(1, 2))); + + int[] result = dijkstra.runDijkstra(0, graph, 2); + int[] expected = {0, 2}; + assertArrayEquals(expected, result); + } + + @Test + void testNegativeWeightThrows() { + Map> graph = new HashMap<>(); + graph.put(0, List.of(new DijkstraPriorityQueue.Edge(1, -1))); + graph.put(1, new ArrayList<>()); + + assertThrows(IllegalArgumentException.class, () -> dijkstra.runDijkstra(0, graph, 2)); + } + + @Test + void testDisconnectedGraph() { + Map> graph = new HashMap<>(); + graph.put(0, new ArrayList<>()); + graph.put(1, new ArrayList<>()); + + int[] result = dijkstra.runDijkstra(0, graph, 2); + int[] expected = {0, Integer.MAX_VALUE}; + assertArrayEquals(expected, result); + } + + @Test + void testEmptyGraph() { + Map> graph = new HashMap<>(); + int[] result = dijkstra.runDijkstra(0, graph, 0); + int[] expected = {}; + assertArrayEquals(expected, result); + } +} \ No newline at end of file