Skip to content

Commit d080b4d

Browse files
authored
Add Floyd Warshall Algorithm (#243)
1 parent 58135f4 commit d080b4d

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using Algorithms.Graph;
2+
using DataStructures.Graph;
3+
using NUnit.Framework;
4+
using FluentAssertions;
5+
6+
namespace Algorithms.Tests.Graph
7+
{
8+
public class FloydWarshallTests
9+
{
10+
[Test]
11+
public void CorrectMatrixTest()
12+
{
13+
var graph = new DirectedWeightedGraph<int>(10);
14+
15+
var vertex1 = graph.AddVertex(1);
16+
17+
var vertex2 = graph.AddVertex(2);
18+
19+
var vertex3 = graph.AddVertex(3);
20+
21+
var vertex4 = graph.AddVertex(4);
22+
23+
var vertex5 = graph.AddVertex(5);
24+
25+
graph.AddEdge(vertex1, vertex2, 3);
26+
27+
graph.AddEdge(vertex1, vertex5, -4);
28+
29+
graph.AddEdge(vertex1, vertex3, 8);
30+
31+
graph.AddEdge(vertex2, vertex5, 7);
32+
33+
graph.AddEdge(vertex2, vertex4, 1);
34+
35+
graph.AddEdge(vertex3, vertex2, 4);
36+
37+
graph.AddEdge(vertex4, vertex3, -5);
38+
39+
graph.AddEdge(vertex4, vertex1, 2);
40+
41+
graph.AddEdge(vertex5, vertex4, 6);
42+
43+
var actualDistances = new double[,]
44+
{
45+
{ 0, 1, -3, 2, -4 },
46+
{ 3, 0, -4, 1, -1 },
47+
{ 7, 4, 0, 5, 3 },
48+
{ 2, -1, -5, 0, -2 },
49+
{ 8, 5, 1, 6, 0 }
50+
};
51+
52+
var floydWarshaller = new FloydWarshall<int>();
53+
54+
floydWarshaller.Run(graph).Should().Equal(actualDistances);
55+
}
56+
}
57+
}

Algorithms/Graph/FloydWarshall.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using DataStructures.Graph;
3+
4+
namespace Algorithms.Graph
5+
{
6+
/// <summary>
7+
/// Floyd Warshall algorithm on directed weighted graph.
8+
/// </summary>
9+
/// <typeparam name="T">generic type of data in graph.</typeparam>
10+
public class FloydWarshall<T>
11+
{
12+
/// <summary>
13+
/// runs the algorithm.
14+
/// </summary>
15+
/// <param name="graph">graph upon which to run.</param>
16+
/// <returns>
17+
/// a 2D array of shortest paths between any two vertices.
18+
/// where there is no path between two vertices - double.PositiveInfinity is placed.
19+
/// </returns>
20+
public double[,] Run(DirectedWeightedGraph<T> graph)
21+
{
22+
var distances = SetupDistances(graph);
23+
var vertexCount = distances.GetLength(0);
24+
for (var k = 0; k < vertexCount; k++)
25+
{
26+
for (var i = 0; i < vertexCount; i++)
27+
{
28+
for (var j = 0; j < vertexCount; j++)
29+
{
30+
distances[i, j] = distances[i, j] > distances[i, k] + distances[k, j]
31+
? distances[i, k] + distances[k, j]
32+
: distances[i, j];
33+
}
34+
}
35+
}
36+
37+
return distances;
38+
}
39+
40+
/// <summary>
41+
/// setup adjacency matrix for use by main algorithm run.
42+
/// </summary>
43+
/// <param name="graph">graph to dissect adjacency matrix from.</param>
44+
/// <returns>the adjacency matrix in the format mentioned in Run.</returns>
45+
private double[,] SetupDistances(DirectedWeightedGraph<T> graph)
46+
{
47+
var distances = new double[graph.Count, graph.Count];
48+
for (int i = 0; i < distances.GetLength(0); i++)
49+
{
50+
for (var j = 0; j < distances.GetLength(0); j++)
51+
{
52+
var dist = graph.AdjacentDistance(graph.Vertices[i] !, graph.Vertices[j] !);
53+
distances[i, j] = dist != 0 ? dist : double.PositiveInfinity;
54+
}
55+
}
56+
57+
for (var i = 0; i < distances.GetLength(0); i++)
58+
{
59+
distances[i, i] = 0;
60+
}
61+
62+
return distances;
63+
}
64+
}
65+
}

DataStructures/Graph/DirectedWeightedGraph.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ public bool AreAdjacent(Vertex<T> startVertex, Vertex<T> endVertex)
142142
return adjacencyMatrix[startVertex.Index, endVertex.Index] != 0;
143143
}
144144

145+
/// <summary>
146+
/// Return the distance between two vertices in the graph.
147+
/// </summary>
148+
/// <param name="startVertex">first vertex in edge.</param>
149+
/// <param name="endVertex">secnod vertex in edge.</param>
150+
/// <returns>distance between the two.</returns>
151+
public double AdjacentDistance(Vertex<T> startVertex, Vertex<T> endVertex)
152+
{
153+
if (AreAdjacent(startVertex, endVertex))
154+
{
155+
return adjacencyMatrix[startVertex.Index, endVertex.Index];
156+
}
157+
158+
return 0;
159+
}
160+
145161
private static void ThrowIfNegativeCapacity(int capacity)
146162
{
147163
if (capacity < 0)

DataStructures/Graph/IDirectedWeightedGraph.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public interface IDirectedWeightedGraph<T>
1414

1515
bool AreAdjacent(Vertex<T> startVertex, Vertex<T> endVertex);
1616

17+
double AdjacentDistance(Vertex<T> startVertex, Vertex<T> endVertex);
18+
1719
IEnumerable<Vertex<T>?> GetNeighbors(Vertex<T> vertex);
1820

1921
void RemoveEdge(Vertex<T> startVertex, Vertex<T> endVertex);

0 commit comments

Comments
 (0)