Skip to content

Commit 102f8c6

Browse files
authored
Add Bellman ford algorithm (TheAlgorithms#416)
1 parent fe4b357 commit 102f8c6

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using Algorithms.Graph;
2+
using DataStructures.Graph;
3+
using NUnit.Framework;
4+
using FluentAssertions;
5+
using System.Collections.Generic;
6+
using System;
7+
8+
namespace Algorithms.Tests.Graph
9+
{
10+
public class BellmanFordTests
11+
{
12+
[Test]
13+
public void CorrectDistancesTest()
14+
{
15+
var graph = new DirectedWeightedGraph<int>(10);
16+
17+
var vertex1 = graph.AddVertex(1);
18+
var vertex2 = graph.AddVertex(2);
19+
var vertex3 = graph.AddVertex(3);
20+
var vertex4 = graph.AddVertex(4);
21+
var vertex5 = graph.AddVertex(5);
22+
23+
graph.AddEdge(vertex1, vertex2, 3);
24+
graph.AddEdge(vertex1, vertex5, -4);
25+
graph.AddEdge(vertex1, vertex3, 8);
26+
graph.AddEdge(vertex2, vertex5, 7);
27+
graph.AddEdge(vertex2, vertex4, 1);
28+
graph.AddEdge(vertex3, vertex2, 4);
29+
graph.AddEdge(vertex4, vertex3, -5);
30+
graph.AddEdge(vertex4, vertex1, 2);
31+
graph.AddEdge(vertex5, vertex4, 6);
32+
33+
var expectedDistances = new Dictionary<Vertex<int>, double>
34+
{
35+
{ vertex1, 0 },
36+
{ vertex2, 1 },
37+
{ vertex3, -3 },
38+
{ vertex4, 2 },
39+
{ vertex5, -4 }
40+
};
41+
42+
var bellmanFord = new BellmanFord<int>(graph, new Dictionary<Vertex<int>, double>(), new Dictionary<Vertex<int>, Vertex<int>?>());
43+
44+
var calculatedDistances = bellmanFord.Run(vertex1);
45+
46+
foreach (var vertex in graph.Vertices)
47+
{
48+
if (vertex != null)
49+
{
50+
calculatedDistances[vertex].Should().BeApproximately(expectedDistances[vertex], 0.001);
51+
}
52+
}
53+
}
54+
55+
[Test]
56+
public void NegativeWeightCycleTest()
57+
{
58+
var graph = new DirectedWeightedGraph<int>(3);
59+
60+
var vertex1 = graph.AddVertex(1);
61+
var vertex2 = graph.AddVertex(2);
62+
var vertex3 = graph.AddVertex(3);
63+
64+
graph.AddEdge(vertex1, vertex2, -1);
65+
graph.AddEdge(vertex2, vertex3, -2);
66+
graph.AddEdge(vertex3, vertex1, -3);
67+
68+
var bellmanFord = new BellmanFord<int>(graph, new Dictionary<Vertex<int>, double>(), new Dictionary<Vertex<int>, Vertex<int>?>());
69+
70+
Action action = () => bellmanFord.Run(vertex1);
71+
72+
action.Should().Throw<InvalidOperationException>().WithMessage("Graph contains a negative weight cycle.");
73+
}
74+
}
75+
}

Algorithms/Graph/BellmanFord.cs

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using DataStructures.Graph;
4+
5+
namespace Algorithms.Graph
6+
{
7+
/// <summary>
8+
/// Bellman-Ford algorithm on directed weighted graph.
9+
/// </summary>
10+
/// <typeparam name="T">Generic type of data in the graph.</typeparam>
11+
public class BellmanFord<T>
12+
{
13+
private readonly DirectedWeightedGraph<T> graph;
14+
private readonly Dictionary<Vertex<T>, double> distances;
15+
private readonly Dictionary<Vertex<T>, Vertex<T>?> predecessors;
16+
17+
public BellmanFord(DirectedWeightedGraph<T> graph, Dictionary<Vertex<T>, double> distances, Dictionary<Vertex<T>, Vertex<T>?> predecessors)
18+
{
19+
this.graph = graph;
20+
this.distances = distances;
21+
this.predecessors = predecessors;
22+
}
23+
24+
/// <summary>
25+
/// Runs the Bellman-Ford algorithm to find the shortest distances from the source vertex to all other vertices.
26+
/// </summary>
27+
/// <param name="sourceVertex">Source vertex for shortest path calculation.</param>
28+
/// <returns>
29+
/// A dictionary containing the shortest distances from the source vertex to all other vertices.
30+
/// If a vertex is unreachable from the source, it will have a value of double.PositiveInfinity.
31+
/// </returns>
32+
public Dictionary<Vertex<T>, double> Run(Vertex<T> sourceVertex)
33+
{
34+
InitializeDistances(sourceVertex);
35+
RelaxEdges();
36+
CheckForNegativeCycles();
37+
return distances;
38+
}
39+
40+
private void InitializeDistances(Vertex<T> sourceVertex)
41+
{
42+
foreach (var vertex in graph.Vertices)
43+
{
44+
if (vertex != null)
45+
{
46+
distances[vertex] = double.PositiveInfinity;
47+
predecessors[vertex] = null;
48+
}
49+
}
50+
51+
distances[sourceVertex] = 0;
52+
}
53+
54+
private void RelaxEdges()
55+
{
56+
int vertexCount = graph.Count;
57+
58+
for (int i = 0; i < vertexCount - 1; i++)
59+
{
60+
foreach (var vertex in graph.Vertices)
61+
{
62+
if (vertex != null)
63+
{
64+
RelaxEdgesForVertex(vertex);
65+
}
66+
}
67+
}
68+
}
69+
70+
private void RelaxEdgesForVertex(Vertex<T> u)
71+
{
72+
foreach (var neighbor in graph.GetNeighbors(u))
73+
{
74+
if (neighbor == null)
75+
{
76+
continue;
77+
}
78+
79+
var v = neighbor;
80+
var weight = graph.AdjacentDistance(u, v);
81+
82+
if (distances[u] + weight < distances[v])
83+
{
84+
distances[v] = distances[u] + weight;
85+
predecessors[v] = u;
86+
}
87+
}
88+
}
89+
90+
private void CheckForNegativeCycles()
91+
{
92+
foreach (var vertex in graph.Vertices)
93+
{
94+
if (vertex != null)
95+
{
96+
CheckForNegativeCyclesForVertex(vertex);
97+
}
98+
}
99+
}
100+
101+
private void CheckForNegativeCyclesForVertex(Vertex<T> u)
102+
{
103+
foreach (var neighbor in graph.GetNeighbors(u))
104+
{
105+
if (neighbor == null)
106+
{
107+
continue;
108+
}
109+
110+
var v = neighbor;
111+
var weight = graph.AdjacentDistance(u, v);
112+
113+
if (distances[u] + weight < distances[v])
114+
{
115+
throw new InvalidOperationException("Graph contains a negative weight cycle.");
116+
}
117+
}
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)