From 61ef6e973e645ffc7218d725fe3ea471a8838744 Mon Sep 17 00:00:00 2001 From: Shubham Padkonde Date: Fri, 23 Oct 2026 22:30:15 +0530 Subject: [PATCH] fix(bellman-ford): bound relaxation work and stop settled passes --- .../bellman-ford/__test__/bellmanFord.test.js | 25 +++++++++++++++++++ .../graph/bellman-ford/bellmanFord.js | 16 +++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/algorithms/graph/bellman-ford/__test__/bellmanFord.test.js b/src/algorithms/graph/bellman-ford/__test__/bellmanFord.test.js index ffa30eba21..cb9dedbfdc 100644 --- a/src/algorithms/graph/bellman-ford/__test__/bellmanFord.test.js +++ b/src/algorithms/graph/bellman-ford/__test__/bellmanFord.test.js @@ -4,6 +4,31 @@ import Graph from '../../../../data-structures/graph/Graph'; import bellmanFord from '../bellmanFord'; describe('bellmanFord', () => { + it('should stop relaxing a complete unit-weight graph after distances settle', () => { + const graph = new Graph(true); + const vertices = Array.from({ length: 12 }, (_, index) => new GraphVertex(`v${index}`)); + let weightReads = 0; + vertices.forEach((start) => { + vertices.forEach((end) => { + if (start !== end) { + const edge = new GraphEdge(start, end, 1); + Object.defineProperty(edge, 'weight', { + get: () => { + weightReads += 1; + return 1; + }, + }); + graph.addEdge(edge); + } + }); + }); + + const { distances } = bellmanFord(graph, vertices[0]); + expect(distances.v0).toBe(0); + vertices.slice(1).forEach((vertex) => expect(distances[vertex.getKey()]).toBe(1)); + expect(weightReads).toBeLessThanOrEqual(2 * graph.getAllEdges().length); + }); + it('should find minimum paths to all vertices for undirected graph', () => { const vertexA = new GraphVertex('A'); const vertexB = new GraphVertex('B'); diff --git a/src/algorithms/graph/bellman-ford/bellmanFord.js b/src/algorithms/graph/bellman-ford/bellmanFord.js index 70e811d992..badf92ca67 100644 --- a/src/algorithms/graph/bellman-ford/bellmanFord.js +++ b/src/algorithms/graph/bellman-ford/bellmanFord.js @@ -17,15 +17,18 @@ export default function bellmanFord(graph, startVertex) { } }); - // We need (|V| - 1) iterations. - for (let iteration = 0; iteration < (graph.getAllVertices().length - 1); iteration += 1) { + // We need at most (|V| - 1) iterations. + const vertexCount = graph.getAllVertices().length; + for (let iteration = 0; iteration < (vertexCount - 1); iteration += 1) { + let relaxed = false; // During each iteration go through all vertices. Object.keys(distances).forEach((vertexKey) => { const vertex = graph.getVertexByKey(vertexKey); // Go through all vertex edges. - graph.getNeighbors(vertex).forEach((neighbor) => { - const edge = graph.findEdge(vertex, neighbor); + vertex.getEdges().forEach((edge) => { + // In an undirected graph, either endpoint may be the current vertex. + const neighbor = edge.startVertex === vertex ? edge.endVertex : edge.startVertex; // Find out if the distance to the neighbor is shorter in this iteration // then in previous one. const distanceToVertex = distances[vertex.getKey()]; @@ -33,9 +36,14 @@ export default function bellmanFord(graph, startVertex) { if (distanceToNeighbor < distances[neighbor.getKey()]) { distances[neighbor.getKey()] = distanceToNeighbor; previousVertices[neighbor.getKey()] = vertex; + relaxed = true; } }); }); + + if (!relaxed) { + break; + } } return {