diff --git a/Algorithms.Dijktra.Tests/Algorithms.Dijktra.Tests.csproj b/Algorithms.Dijktra.Tests/Algorithms.Dijktra.Tests.csproj new file mode 100644 index 00000000..e59c2c5f --- /dev/null +++ b/Algorithms.Dijktra.Tests/Algorithms.Dijktra.Tests.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/Algorithms.Dijktra.Tests/DijkstraUTests.cs b/Algorithms.Dijktra.Tests/DijkstraUTests.cs new file mode 100644 index 00000000..6a82ff1d --- /dev/null +++ b/Algorithms.Dijktra.Tests/DijkstraUTests.cs @@ -0,0 +1,201 @@ +using Algorithms.Graph.Dijkstra; +using DataStructures.Graph; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Algorithms.Dijktra.Tests +{ + [TestFixture] + public class DijkstraUTests + { + [Test] + public void DijkstraTest1_GraphIsNull() + { + var graph = new DirectedWeightedGraph(5); + var a = graph.AddVertex('A'); + + Func[]> action = () => DijkstraAlgorithm.GenerateShortestPath(null!, a); + + action.Should().Throw() + .WithMessage($"Value cannot be null. (Parameter '{nameof(graph)}')"); + } + + [Test] + public void DijkstraTest2_VertexDoesntBelongToGraph() + { + var graph = new DirectedWeightedGraph(5); + var startVertex = graph.AddVertex('A'); + + Func[]> action = () => DijkstraAlgorithm.GenerateShortestPath( + new DirectedWeightedGraph(5), startVertex); + + action.Should().Throw() + .WithMessage($"Value cannot be null. (Parameter '{nameof(graph)}')"); + } + + [Test] + public void DijkstraTest3_BasicGraph() + { + var graph = new DirectedWeightedGraph(4); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + + graph.AddEdge(a, b, 4); + graph.AddEdge(a, c, 7); + graph.AddEdge(b, c, 2); + graph.AddEdge(b, d, 3); + graph.AddEdge(c, d, 5); + + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + shortestPathList.Length.Should().Be(4); + + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {a} is Distance: {0}"); + + shortestPathList[1].PreviousVertex.Should().Be(a); + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(4); + shortestPathList[1].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {b} is Distance: {4}"); + + shortestPathList[2].PreviousVertex.Should().Be(b); + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(6); + shortestPathList[2].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {c} is Distance: {6}"); + + shortestPathList[3].PreviousVertex.Should().Be(b); + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(7); + shortestPathList[3].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {d} is Distance: {7}"); + } + + [Test] + public void DijkstraTest4_SparseGraph() + { + var graph = new DirectedWeightedGraph(6); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + var e = graph.AddVertex('E'); + var f = graph.AddVertex('F'); + + graph.AddEdge(a, f, 4); + + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + shortestPathList.Length.Should().Be(6); + + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {a} is Distance: {0}"); + + shortestPathList[1].PreviousVertex.Should().Be(null); + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(double.MaxValue); + shortestPathList[1].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {b} is Distance: {double.MaxValue}"); + + shortestPathList[2].PreviousVertex.Should().Be(null); + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(double.MaxValue); + shortestPathList[2].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {c} is Distance: {double.MaxValue}"); + + shortestPathList[3].PreviousVertex.Should().Be(null); + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(double.MaxValue); + shortestPathList[3].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {d} is Distance: {double.MaxValue}"); + + shortestPathList[4].PreviousVertex.Should().Be(null); + shortestPathList[4].Vertex.Should().Be(e); + shortestPathList[4].Distance.Should().Be(double.MaxValue); + shortestPathList[4].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {e} is Distance: {double.MaxValue}"); + + shortestPathList[5].PreviousVertex.Should().Be(a); + shortestPathList[5].Vertex.Should().Be(f); + shortestPathList[5].Distance.Should().Be(4); + shortestPathList[5].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {f} is Distance: {4}"); + } + + [Test] + public void DijkstraTest5_DenseGraph() + { + var graph = new DirectedWeightedGraph(6); + var a = graph.AddVertex('A'); + var b = graph.AddVertex('B'); + var c = graph.AddVertex('C'); + var d = graph.AddVertex('D'); + var e = graph.AddVertex('E'); + var f = graph.AddVertex('F'); + + graph.AddEdge(a, b, 1); + graph.AddEdge(a, d, 2); + graph.AddEdge(b, c, 1); + graph.AddEdge(b, d, 2); + graph.AddEdge(b, e, 3); + graph.AddEdge(c, e, 2); + graph.AddEdge(c, f, 1); + graph.AddEdge(d, e, 1); + graph.AddEdge(e, f, 1); + + var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a); + shortestPathList.Length.Should().Be(6); + + shortestPathList[0].PreviousVertex.Should().Be(a); + shortestPathList[0].Vertex.Should().Be(a); + shortestPathList[0].Distance.Should().Be(0); + shortestPathList[0].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {a} is Distance: {0}"); + + shortestPathList[1].PreviousVertex.Should().Be(a); + shortestPathList[1].Vertex.Should().Be(b); + shortestPathList[1].Distance.Should().Be(1); + shortestPathList[1].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {b} is Distance: {1}"); + + shortestPathList[2].PreviousVertex.Should().Be(b); + shortestPathList[2].Vertex.Should().Be(c); + shortestPathList[2].Distance.Should().Be(2); + shortestPathList[2].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {c} is Distance: {2}"); + + shortestPathList[3].PreviousVertex.Should().Be(a); + shortestPathList[3].Vertex.Should().Be(d); + shortestPathList[3].Distance.Should().Be(2); + shortestPathList[3].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {d} is Distance: {2}"); + + shortestPathList[4].PreviousVertex.Should().Be(d); + shortestPathList[4].Vertex.Should().Be(e); + shortestPathList[4].Distance.Should().Be(3); + shortestPathList[4].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {e} is Distance: {3}"); + + shortestPathList[5].PreviousVertex.Should().Be(c); + shortestPathList[5].Vertex.Should().Be(f); + shortestPathList[5].Distance.Should().Be(3); + shortestPathList[5].PrintDistance().Should() + .Be($"Start from Vertex: {a} to Vertex {f} is Distance: {3}"); + + } + } + +} diff --git a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs index 8aee1f0f..4bcf7753 100644 --- a/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs +++ b/Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs @@ -73,11 +73,11 @@ private static DistanceModel[] InitializeDistanceArray( { var distArray = new DistanceModel[graph.Count]; - distArray[startVertex.Index] = new DistanceModel(startVertex, startVertex, 0); + distArray[startVertex.Index] = new DistanceModel(startVertex, startVertex, startVertex, 0); foreach (var vertex in graph.Vertices.Where(x => x != null && !x.Equals(startVertex))) { - distArray[vertex!.Index] = new DistanceModel(vertex, null, double.MaxValue); + distArray[vertex!.Index] = new DistanceModel(vertex, null, startVertex, double.MaxValue); } return distArray; diff --git a/Algorithms/Graph/Dijkstra/DistanceModel.cs b/Algorithms/Graph/Dijkstra/DistanceModel.cs index 133fa6d1..e99de447 100644 --- a/Algorithms/Graph/Dijkstra/DistanceModel.cs +++ b/Algorithms/Graph/Dijkstra/DistanceModel.cs @@ -13,6 +13,8 @@ public class DistanceModel public Vertex? PreviousVertex { get; set; } + public Vertex? StartVertex { get; set; } + public double Distance { get; set; } public DistanceModel(Vertex? vertex, Vertex? previousVertex, double distance) @@ -22,6 +24,17 @@ public DistanceModel(Vertex? vertex, Vertex? previousVertex, double distan Distance = distance; } + public DistanceModel(Vertex? vertex, Vertex? previousVertex, Vertex? startVertex, double distance) + { + Vertex = vertex; + PreviousVertex = previousVertex; + Distance = distance; + StartVertex = startVertex; + } + public override string ToString() => - $"Vertex: {Vertex} - Distance: {Distance} - Previous: {PreviousVertex}"; + $"From Previous Vertex: {PreviousVertex} to Vertex {Vertex} is Distance: {Distance}"; + + public string PrintDistance() => + $"Start from Vertex: {StartVertex} to Vertex {Vertex} is Distance: {Distance}"; } diff --git a/C-Sharp.sln b/C-Sharp.sln index 857df3e5..4927092e 100644 --- a/C-Sharp.sln +++ b/C-Sharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.352 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35818.85 d17.13 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{DAB16DEC-AF31-4B59-8DD5-5C76C1A23052}" ProjectSection(SolutionItems) = preProject @@ -21,16 +21,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Configs", "Configs", "{F3AC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Algorithms", "Algorithms\Algorithms.csproj", "{EC967159-73D8-4E44-8455-E2D16DB4CBBB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Algorithms.Tests", "Algorithms.Tests\Algorithms.Tests.csproj", "{56817595-1552-409B-93B8-F8082F8490A5}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataStructures", "DataStructures\DataStructures.csproj", "{E9C27C73-1F95-4C6E-9DB4-F8585426A850}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataStructures.Tests", "DataStructures.Tests\DataStructures.Tests.csproj", "{39174100-3A6E-45B2-9AA9-7C69764C0750}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utilities", "Utilities\Utilities.csproj", "{3A41157D-296D-4BFC-A34E-91B5ED7F0905}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utilities.Tests", "Utilities.Tests\Utilities.Tests.csproj", "{ED47E2E2-045C-41DD-B555-A64944D6C2F5}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTest", "UnitTest", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Algorithms.Dijktra.Tests", "Algorithms.Dijktra.Tests\Algorithms.Dijktra.Tests.csproj", "{D64DF824-C9E7-4696-BA83-1B87B7C4B5E1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,18 +41,10 @@ Global {EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC967159-73D8-4E44-8455-E2D16DB4CBBB}.Release|Any CPU.Build.0 = Release|Any CPU - {56817595-1552-409B-93B8-F8082F8490A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56817595-1552-409B-93B8-F8082F8490A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56817595-1552-409B-93B8-F8082F8490A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56817595-1552-409B-93B8-F8082F8490A5}.Release|Any CPU.Build.0 = Release|Any CPU {E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Debug|Any CPU.Build.0 = Debug|Any CPU {E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Release|Any CPU.ActiveCfg = Release|Any CPU {E9C27C73-1F95-4C6E-9DB4-F8585426A850}.Release|Any CPU.Build.0 = Release|Any CPU - {39174100-3A6E-45B2-9AA9-7C69764C0750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39174100-3A6E-45B2-9AA9-7C69764C0750}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39174100-3A6E-45B2-9AA9-7C69764C0750}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39174100-3A6E-45B2-9AA9-7C69764C0750}.Release|Any CPU.Build.0 = Release|Any CPU {3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Debug|Any CPU.Build.0 = Debug|Any CPU {3A41157D-296D-4BFC-A34E-91B5ED7F0905}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -61,10 +53,17 @@ Global {ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED47E2E2-045C-41DD-B555-A64944D6C2F5}.Release|Any CPU.Build.0 = Release|Any CPU + {D64DF824-C9E7-4696-BA83-1B87B7C4B5E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D64DF824-C9E7-4696-BA83-1B87B7C4B5E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D64DF824-C9E7-4696-BA83-1B87B7C4B5E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D64DF824-C9E7-4696-BA83-1B87B7C4B5E1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D64DF824-C9E7-4696-BA83-1B87B7C4B5E1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9D733AD8-7C69-4F40-ADBB-2DD8EA9F18FB} EndGlobalSection