chore(CSharp): Implemented Dijkstras Algorithm to Find the Shortest Path (#489)

pull/498/head
Waqar Hassan Khan 2021-09-28 06:11:58 +06:00 committed by GitHub
parent adaf66ebb6
commit 06ab1015e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 191 additions and 0 deletions

View File

@ -31,3 +31,4 @@ For running the `.cs` file please using [.Net Finddle](https://dotnetfiddle.net/
## Graph
- [Depth First Search](src/Graph/depth-first-search.cs)
- [Kruskals Algorithm to Find Minimum Spanning Tree](src/Graph/kruskals-algorithm.cs)
- [Dijkstras Algorithm to Find Shortest Path](src/Graph/dijkstra.cs)

View File

@ -4,4 +4,8 @@
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OptimizedPriorityQueue" Version="5.1.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,132 @@
using Priority_Queue;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Algorithms.Graph
{
public class Dijkstra
{
class Graph
{
private int _totalNodes;
private bool _directedGraph;
private Dictionary<int, List<Tuple<int, int>>> _edges;
private const int INFINITY = (int)1e9;
public Graph(int totalNodes, bool directedGraph)
{
_totalNodes = totalNodes;
_directedGraph = directedGraph;
_edges = new Dictionary<int, List<Tuple<int, int>>>();
}
public void AddEdge(int source, int destination, int weight)
{
if(!_edges.ContainsKey(source))
{
_edges.Add(source, new List<Tuple<int, int>>());
}
_edges[source].Add(new Tuple<int, int>(destination, weight));
if(!_directedGraph)
{
if(!_edges.ContainsKey(destination))
{
_edges.Add(destination, new List<Tuple<int, int>>());
}
_edges[destination].Add(new Tuple<int, int>(source, weight));
}
}
public Object ShortestPath(int source, int destination)
{
List<int> parent = Enumerable.Repeat(-1, _totalNodes + 1).ToList();
List<int> distance = Enumerable.Repeat(INFINITY, _totalNodes + 1).ToList();
List<bool> visited = Enumerable.Repeat(false, _totalNodes + 1).ToList();
SimplePriorityQueue<int> pq = new SimplePriorityQueue<int>();
pq.Enqueue(source, 0);
distance[source] = 0;
while(pq.Count > 0)
{
int u = pq.Dequeue();
if(visited[u] == true || !_edges.ContainsKey(u))
{
continue;
}
foreach(var edge in _edges[u])
{
if(!visited[edge.Item1] && distance[edge.Item1] > distance[u] + edge.Item2)
{
distance[edge.Item1] = distance[u] + edge.Item2;
pq.Enqueue(edge.Item1, distance[edge.Item1]);
parent[edge.Item1] = u;
}
}
visited[u] = true;
}
List<int> shortestPath = new List<int>();
int finalDestination = destination;
if(distance[destination] != INFINITY)
{
while (true)
{
shortestPath.Add(finalDestination);
finalDestination = parent[finalDestination];
if (finalDestination == -1)
{
break;
}
}
shortestPath.Reverse();
}
Object result = new
{
distance = distance[destination] == INFINITY ? -1 : distance[destination],
path = shortestPath
};
return result;
}
}
public static Object RunDijkstra(int totalNodes, bool isDirected, int source, int destination, List<Tuple<int, int, int>> edges)
{
Graph graph = new Graph(totalNodes, isDirected);
foreach(var edge in edges)
{
graph.AddEdge(edge.Item1, edge.Item2, edge.Item3);
}
return graph.ShortestPath(source, destination);
}
public static void Main()
{
var result = RunDijkstra(5, true, 1, 5, new List<Tuple<int, int, int>> {
new Tuple<int, int, int>(1, 2, 2),
new Tuple<int, int, int>(2, 5, 8),
new Tuple<int, int, int>(2, 3, 4),
new Tuple<int, int, int>(4, 1, 1),
new Tuple<int, int, int>(3, 4, 3),
new Tuple<int, int, int>(3, 5, 1)
});
int distance = (int)result.GetType().GetProperty("distance").GetValue(result, null);
List<int> path = (List<int>)result.GetType().GetProperty("path").GetValue(result, null);
Console.WriteLine($"Distance: {distance}");
Console.WriteLine($"Path: {string.Join("->", path)}");
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using NUnit.Framework;
using System.Collections.Generic;
namespace Algorithms.Tests.Graph
{
[TestFixture]
public class Dijkstra
{
static object[] TestCasesForDijkstra =
{
new object[]
{
5, false, 1, 5, new List<Tuple<int, int, int>> {
new Tuple<int, int, int>(1, 2, 2),
new Tuple<int, int, int>(2, 5, 5),
new Tuple<int, int, int>(2, 3, 4),
new Tuple<int, int, int>(1, 4, 1),
new Tuple<int, int, int>(4, 3, 3),
new Tuple<int, int, int>(3, 5, 1)
},
5
},
new object[]
{
5, true, 1, 5, new List<Tuple<int, int, int>> {
new Tuple<int, int, int>(1, 2, 2),
new Tuple<int, int, int>(2, 5, 8),
new Tuple<int, int, int>(2, 3, 4),
new Tuple<int, int, int>(4, 1, 1),
new Tuple<int, int, int>(3, 4, 3),
new Tuple<int, int, int>(3, 5, 1)
},
7
},
new object[]
{
3, false, 1, 3, new List<Tuple<int, int, int>> {
new Tuple<int, int, int>(1, 2, 1)
},
-1
},
};
[TestCaseSource(nameof(TestCasesForDijkstra))]
public void TestDijkstra_ShouldGetExpectedResult(int totalNodes, bool isDirected, int source, int destination, List<Tuple<int, int, int>> edges, int expected)
{
var result = Algorithms.Graph.Dijkstra.RunDijkstra(totalNodes, isDirected, source, destination, edges);
int distance = (int)result.GetType().GetProperty("distance").GetValue(result, null);
Assert.AreEqual(expected, distance);
}
}
}