From 06ab1015e878e49add172c3910ef0990d40c6dc9 Mon Sep 17 00:00:00 2001 From: Waqar Hassan Khan Date: Tue, 28 Sep 2021 06:11:58 +0600 Subject: [PATCH] chore(CSharp): Implemented Dijkstras Algorithm to Find the Shortest Path (#489) --- algorithms/CSharp/README.md | 1 + algorithms/CSharp/src/Algorithms.csproj | 4 + algorithms/CSharp/src/Graph/dijkstra.cs | 132 +++++++++++++++++++++++ algorithms/CSharp/test/Graph/dijkstra.cs | 54 ++++++++++ 4 files changed, 191 insertions(+) create mode 100644 algorithms/CSharp/src/Graph/dijkstra.cs create mode 100644 algorithms/CSharp/test/Graph/dijkstra.cs diff --git a/algorithms/CSharp/README.md b/algorithms/CSharp/README.md index 1c96ae38..3839779a 100644 --- a/algorithms/CSharp/README.md +++ b/algorithms/CSharp/README.md @@ -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) diff --git a/algorithms/CSharp/src/Algorithms.csproj b/algorithms/CSharp/src/Algorithms.csproj index cb631906..e287115e 100644 --- a/algorithms/CSharp/src/Algorithms.csproj +++ b/algorithms/CSharp/src/Algorithms.csproj @@ -4,4 +4,8 @@ netcoreapp3.1 + + + + diff --git a/algorithms/CSharp/src/Graph/dijkstra.cs b/algorithms/CSharp/src/Graph/dijkstra.cs new file mode 100644 index 00000000..8a617424 --- /dev/null +++ b/algorithms/CSharp/src/Graph/dijkstra.cs @@ -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>> _edges; + private const int INFINITY = (int)1e9; + + public Graph(int totalNodes, bool directedGraph) + { + _totalNodes = totalNodes; + _directedGraph = directedGraph; + _edges = new Dictionary>>(); + } + + public void AddEdge(int source, int destination, int weight) + { + if(!_edges.ContainsKey(source)) + { + _edges.Add(source, new List>()); + } + _edges[source].Add(new Tuple(destination, weight)); + + if(!_directedGraph) + { + if(!_edges.ContainsKey(destination)) + { + _edges.Add(destination, new List>()); + } + _edges[destination].Add(new Tuple(source, weight)); + } + } + + public Object ShortestPath(int source, int destination) + { + List parent = Enumerable.Repeat(-1, _totalNodes + 1).ToList(); + List distance = Enumerable.Repeat(INFINITY, _totalNodes + 1).ToList(); + List visited = Enumerable.Repeat(false, _totalNodes + 1).ToList(); + + SimplePriorityQueue pq = new SimplePriorityQueue(); + 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 shortestPath = new List(); + 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> 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> { + new Tuple(1, 2, 2), + new Tuple(2, 5, 8), + new Tuple(2, 3, 4), + new Tuple(4, 1, 1), + new Tuple(3, 4, 3), + new Tuple(3, 5, 1) + }); + + int distance = (int)result.GetType().GetProperty("distance").GetValue(result, null); + List path = (List)result.GetType().GetProperty("path").GetValue(result, null); + + Console.WriteLine($"Distance: {distance}"); + Console.WriteLine($"Path: {string.Join("->", path)}"); + } + } +} diff --git a/algorithms/CSharp/test/Graph/dijkstra.cs b/algorithms/CSharp/test/Graph/dijkstra.cs new file mode 100644 index 00000000..0c4c04be --- /dev/null +++ b/algorithms/CSharp/test/Graph/dijkstra.cs @@ -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> { + new Tuple(1, 2, 2), + new Tuple(2, 5, 5), + new Tuple(2, 3, 4), + new Tuple(1, 4, 1), + new Tuple(4, 3, 3), + new Tuple(3, 5, 1) + }, + 5 + }, + new object[] + { + 5, true, 1, 5, new List> { + new Tuple(1, 2, 2), + new Tuple(2, 5, 8), + new Tuple(2, 3, 4), + new Tuple(4, 1, 1), + new Tuple(3, 4, 3), + new Tuple(3, 5, 1) + }, + 7 + }, + new object[] + { + 3, false, 1, 3, new List> { + new Tuple(1, 2, 1) + }, + -1 + }, + }; + + [TestCaseSource(nameof(TestCasesForDijkstra))] + public void TestDijkstra_ShouldGetExpectedResult(int totalNodes, bool isDirected, int source, int destination, List> 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); + } + } +}