diff --git a/src/main/java/com/thealgorithms/graph/BellmanFord.java b/src/main/java/com/thealgorithms/graph/BellmanFord.java
new file mode 100644
index 000000000000..f87b456a7976
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/BellmanFord.java
@@ -0,0 +1,193 @@
+package com.thealgorithms.graph;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Implementation of the Bellman-Ford algorithm for finding shortest paths from a single source
+ * vertex to all other vertices in a weighted directed graph. Unlike Dijkstra's algorithm,
+ * Bellman-Ford can handle graphs with negative weight edges and can detect negative weight cycles.
+ *
+ *
Time Complexity: O(V * E) where V is the number of vertices and E is the number of edges
+ * Space Complexity: O(V)
+ *
+ *
Algorithm Steps:
+ * 1. Initialize distances from source to all vertices as infinite and distance to source as 0
+ * 2. Relax all edges V-1 times (where V is the number of vertices)
+ * 3. Check for negative weight cycles by attempting one more relaxation
+ *
+ * @author vardhan30016
+ * @see Bellman-Ford Algorithm
+ */
+public final class BellmanFord {
+
+ private BellmanFord() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Represents a weighted edge in the graph.
+ */
+ public static class Edge {
+ private final int source;
+ private final int destination;
+ private final int weight;
+
+ /**
+ * Creates a new edge.
+ *
+ * @param source the source vertex
+ * @param destination the destination vertex
+ * @param weight the weight of the edge
+ */
+ public Edge(int source, int destination, int weight) {
+ this.source = source;
+ this.destination = destination;
+ this.weight = weight;
+ }
+
+ public int getSource() {
+ return source;
+ }
+
+ public int getDestination() {
+ return destination;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+ }
+
+ /**
+ * Represents the result of the Bellman-Ford algorithm.
+ */
+ public static class Result {
+ private final int[] distances;
+ private final int[] predecessors;
+ private final boolean hasNegativeCycle;
+
+ /**
+ * Creates a new result.
+ *
+ * @param distances array of shortest distances from source to each vertex
+ * @param predecessors array of predecessor vertices in shortest paths
+ * @param hasNegativeCycle true if the graph contains a negative weight cycle
+ */
+ public Result(int[] distances, int[] predecessors, boolean hasNegativeCycle) {
+ this.distances = Arrays.copyOf(distances, distances.length);
+ this.predecessors = Arrays.copyOf(predecessors, predecessors.length);
+ this.hasNegativeCycle = hasNegativeCycle;
+ }
+
+ /**
+ * Gets the shortest distance to a vertex.
+ *
+ * @param vertex the target vertex
+ * @return the shortest distance from source to the vertex, or Integer.MAX_VALUE if unreachable
+ */
+ public int getDistance(int vertex) {
+ return distances[vertex];
+ }
+
+ /**
+ * Gets all distances.
+ *
+ * @return array of distances from source to all vertices
+ */
+ public int[] getDistances() {
+ return Arrays.copyOf(distances, distances.length);
+ }
+
+ /**
+ * Gets the shortest path to a vertex.
+ *
+ * @param vertex the target vertex
+ * @return list of vertices in the shortest path from source to target
+ * @throws IllegalStateException if the graph contains a negative cycle
+ * @throws IllegalArgumentException if the vertex is unreachable
+ */
+ public List getPath(int vertex) {
+ if (hasNegativeCycle) {
+ throw new IllegalStateException("Graph contains a negative weight cycle");
+ }
+ if (distances[vertex] == Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("Vertex " + vertex + " is unreachable from source");
+ }
+
+ List path = new ArrayList<>();
+ for (int v = vertex; v != -1; v = predecessors[v]) {
+ path.add(0, v);
+ }
+ return path;
+ }
+
+ /**
+ * Checks if the graph contains a negative weight cycle.
+ *
+ * @return true if a negative cycle exists, false otherwise
+ */
+ public boolean hasNegativeCycle() {
+ return hasNegativeCycle;
+ }
+ }
+
+ /**
+ * Finds shortest paths from a source vertex to all other vertices using the Bellman-Ford algorithm.
+ *
+ * @param vertices the number of vertices in the graph
+ * @param edges list of edges in the graph
+ * @param source the source vertex (0-indexed)
+ * @return Result object containing distances, paths, and negative cycle information
+ * @throws IllegalArgumentException if vertices is non-positive or source is invalid
+ */
+ public static Result findShortestPaths(int vertices, Iterable edges, int source) {
+ if (vertices <= 0) {
+ throw new IllegalArgumentException("Number of vertices must be positive");
+ }
+ if (source < 0 || source >= vertices) {
+ throw new IllegalArgumentException("Source vertex is out of bounds");
+ }
+
+ // Step 1: Initialize distances and predecessors
+ int[] distances = new int[vertices];
+ int[] predecessors = new int[vertices];
+ Arrays.fill(distances, Integer.MAX_VALUE);
+ Arrays.fill(predecessors, -1);
+ distances[source] = 0;
+
+ // Step 2: Relax all edges V-1 times
+ for (int i = 0; i < vertices - 1; i++) {
+ boolean updated = false;
+ for (Edge edge : edges) {
+ if (distances[edge.getSource()] != Integer.MAX_VALUE) {
+ int newDistance = distances[edge.getSource()] + edge.getWeight();
+ if (newDistance < distances[edge.getDestination()]) {
+ distances[edge.getDestination()] = newDistance;
+ predecessors[edge.getDestination()] = edge.getSource();
+ updated = true;
+ }
+ }
+ }
+ // Early termination optimization: if no updates in this iteration, we're done
+ if (!updated) {
+ break;
+ }
+ }
+
+ // Step 3: Check for negative weight cycles
+ boolean hasNegativeCycle = false;
+ for (Edge edge : edges) {
+ if (distances[edge.getSource()] != Integer.MAX_VALUE) {
+ int newDistance = distances[edge.getSource()] + edge.getWeight();
+ if (newDistance < distances[edge.getDestination()]) {
+ hasNegativeCycle = true;
+ break;
+ }
+ }
+ }
+
+ return new Result(distances, predecessors, hasNegativeCycle);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/graph/BellmanFordTest.java b/src/test/java/com/thealgorithms/graph/BellmanFordTest.java
new file mode 100644
index 000000000000..3e57718a660d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graph/BellmanFordTest.java
@@ -0,0 +1,137 @@
+package com.thealgorithms.graph;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test class for Bellman-Ford algorithm implementation
+ */
+class BellmanFordTest {
+
+ @Test
+ void testSimpleGraph() {
+ List edges = new ArrayList<>();
+ edges.add(new BellmanFord.Edge(0, 1, 6));
+ edges.add(new BellmanFord.Edge(0, 2, 7));
+ edges.add(new BellmanFord.Edge(1, 2, 8));
+ edges.add(new BellmanFord.Edge(1, 3, 5));
+ edges.add(new BellmanFord.Edge(1, 4, -4));
+ edges.add(new BellmanFord.Edge(2, 3, -3));
+ edges.add(new BellmanFord.Edge(2, 4, 9));
+ edges.add(new BellmanFord.Edge(3, 1, -2));
+ edges.add(new BellmanFord.Edge(4, 0, 2));
+ edges.add(new BellmanFord.Edge(4, 3, 7));
+
+ BellmanFord.Result result = BellmanFord.findShortestPaths(5, edges, 0);
+
+ assertFalse(result.hasNegativeCycle());
+ assertArrayEquals(new int[] {0, 2, 7, 4, -2}, result.getDistances());
+ }
+
+ @Test
+ void testGraphWithNegativeCycle() {
+ List edges = new ArrayList<>();
+ edges.add(new BellmanFord.Edge(0, 1, 1));
+ edges.add(new BellmanFord.Edge(1, 2, -3));
+ edges.add(new BellmanFord.Edge(2, 0, 1));
+
+ BellmanFord.Result result = BellmanFord.findShortestPaths(3, edges, 0);
+
+ assertTrue(result.hasNegativeCycle());
+ }
+
+ @Test
+ void testDisconnectedGraph() {
+ List edges = new ArrayList<>();
+ edges.add(new BellmanFord.Edge(0, 1, 5));
+ edges.add(new BellmanFord.Edge(2, 3, 2));
+
+ BellmanFord.Result result = BellmanFord.findShortestPaths(4, edges, 0);
+
+ assertEquals(0, result.getDistance(0));
+ assertEquals(5, result.getDistance(1));
+ assertEquals(Integer.MAX_VALUE, result.getDistance(2));
+ assertEquals(Integer.MAX_VALUE, result.getDistance(3));
+ }
+
+ @Test
+ void testSingleVertex() {
+ List edges = new ArrayList<>();
+ BellmanFord.Result result = BellmanFord.findShortestPaths(1, edges, 0);
+
+ assertFalse(result.hasNegativeCycle());
+ assertArrayEquals(new int[] {0}, result.getDistances());
+ }
+
+ @Test
+ void testPathReconstruction() {
+ List edges = new ArrayList<>();
+ edges.add(new BellmanFord.Edge(0, 1, 4));
+ edges.add(new BellmanFord.Edge(0, 2, 2));
+ edges.add(new BellmanFord.Edge(1, 2, 1));
+ edges.add(new BellmanFord.Edge(2, 3, 3));
+
+ BellmanFord.Result result = BellmanFord.findShortestPaths(4, edges, 0);
+
+ List path = result.getPath(3);
+ assertNotNull(path);
+ assertEquals(Arrays.asList(0, 2, 3), path);
+ }
+
+ @Test
+ void testNegativeWeights() {
+ List edges = new ArrayList<>();
+ edges.add(new BellmanFord.Edge(0, 1, 5));
+ edges.add(new BellmanFord.Edge(1, 2, -2));
+ edges.add(new BellmanFord.Edge(2, 3, 3));
+
+ BellmanFord.Result result = BellmanFord.findShortestPaths(4, edges, 0);
+
+ assertFalse(result.hasNegativeCycle());
+ assertEquals(0, result.getDistance(0));
+ assertEquals(5, result.getDistance(1));
+ assertEquals(3, result.getDistance(2));
+ assertEquals(6, result.getDistance(3));
+ }
+
+ @Test
+ void testInvalidSource() {
+ List edges = new ArrayList<>();
+ edges.add(new BellmanFord.Edge(0, 1, 5));
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ BellmanFord.findShortestPaths(2, edges, -1);
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ BellmanFord.findShortestPaths(2, edges, 2);
+ });
+ }
+
+ @Test
+ void testInvalidVertexCount() {
+ List edges = new ArrayList<>();
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ BellmanFord.findShortestPaths(0, edges, 0);
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ BellmanFord.findShortestPaths(-1, edges, 0);
+ });
+ }
+
+ @Test
+ void testNullEdges() {
+ assertThrows(NullPointerException.class, () -> {
+ BellmanFord.findShortestPaths(3, null, 0);
+ });
+ }
+}