diff --git a/algorithms/CSharp/README.md b/algorithms/CSharp/README.md index f16eb7f8..109bb20e 100644 --- a/algorithms/CSharp/README.md +++ b/algorithms/CSharp/README.md @@ -26,3 +26,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) diff --git a/algorithms/CSharp/src/Graph/kruskals-algorithm.cs b/algorithms/CSharp/src/Graph/kruskals-algorithm.cs new file mode 100644 index 00000000..7c9139ef --- /dev/null +++ b/algorithms/CSharp/src/Graph/kruskals-algorithm.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Algorithms.Graph +{ + public class KruskalsAlgorithm + { + public class DisjointSetUnion + { + private int[] parent, rank; + public DisjointSetUnion(int totalNodes) + { + rank = Enumerable.Repeat(1, totalNodes + 1).ToArray(); + parent = Enumerable.Range(0, totalNodes + 1).ToArray(); + } + + public void Union(int nodeA, int nodeB) + { + int parentA = Find(nodeA); + int parentB = Find(nodeB); + + if(rank[parentA] > rank[parentB]) + { + parent[parentB] = parentA; + rank[parentA] += rank[parentB]; + } + else + { + parent[parentA] = parentB; + rank[parentB] += rank[parentA]; + } + } + + public int Find(int node) + { + if(parent[node] == node) + { + return node; + } + + return parent[node] = Find(parent[node]); + } + } + + public class Graph + { + private DisjointSetUnion _nodesTaken; + private List> edges; + public Graph(int totalNodes) + { + _nodesTaken = new DisjointSetUnion(totalNodes); + edges = new List>(); + } + + public void AddEdge(int source, int destination, int weight) => + edges.Add(new Tuple(source, destination, weight)); + + + public List> GetMST() + { + edges = (from edge in edges + orderby edge.Item3 + select edge).ToList(); + + List> results = new List>(); + foreach(var edge in edges) + { + if(_nodesTaken.Find(edge.Item1) != _nodesTaken.Find(edge.Item2)) + { + _nodesTaken.Union(edge.Item1, edge.Item2); + results.Add(new Tuple(edge.Item1, edge.Item2, edge.Item3)); + } + } + + return results; + } + } + + public static Object KruskalDriver(int totalNodes, List> edges) + { + Graph graph = new Graph(totalNodes); + + foreach(var edge in edges) + { + graph.AddEdge(edge.Item1, edge.Item2, edge.Item3); + } + + var results = graph.GetMST(); + int totalWeight = 0; + + foreach(var edge in results) + { + totalWeight += edge.Item3; + } + + Object ret = new { + weight = totalWeight, + edges = results + }; + + return ret; + } + + public static void Main() + { + List> edges = new List>() + { + new Tuple(1, 2, 4), + new Tuple(1, 8, 8), + new Tuple(2, 8, 11), + new Tuple(2, 3, 8), + new Tuple(3, 9, 2), + new Tuple(8, 9, 7), + new Tuple(8, 7, 1), + new Tuple(7, 9, 6), + new Tuple(3, 4, 7), + new Tuple(3, 6, 4), + new Tuple(6, 7, 2), + new Tuple(4, 6, 14), + new Tuple(4, 5, 9), + new Tuple(5, 6, 10) + }; + + var result = KruskalDriver(9, edges); + var propertyInfo = result.GetType().GetProperty("weight"); + var weight = propertyInfo.GetValue(result, null); + Console.WriteLine(weight); + } + } +} diff --git a/algorithms/CSharp/test/Graph/kruskals-algortihm.cs b/algorithms/CSharp/test/Graph/kruskals-algortihm.cs new file mode 100644 index 00000000..fe3659f4 --- /dev/null +++ b/algorithms/CSharp/test/Graph/kruskals-algortihm.cs @@ -0,0 +1,61 @@ +using System; +using NUnit.Framework; +using System.Collections.Generic; + +namespace Algorithms.Tests.Graph +{ + [TestFixture] + class KruskalsAlgortihm + { + static Object[] TestCasesForKruskalsAlgorithm = + { + new object[] + { + 9, + new List>() + { + new Tuple(1, 2, 4), + new Tuple(1, 8, 8), + new Tuple(2, 8, 11), + new Tuple(2, 3, 8), + new Tuple(3, 9, 2), + new Tuple(8, 9, 7), + new Tuple(8, 7, 1), + new Tuple(7, 9, 6), + new Tuple(3, 4, 7), + new Tuple(3, 6, 4), + new Tuple(6, 7, 2), + new Tuple(4, 6, 14), + new Tuple(4, 5, 9), + new Tuple(5, 6, 10) + }, + 37 + }, + + new object[] + { + 4, + new List>() + { + new Tuple(1, 2, 4), + new Tuple(1, 3, 1), + new Tuple(1, 4, 2), + new Tuple(2, 3, 6), + new Tuple(2, 4, 1), + new Tuple(3, 4, 7) + }, + 4 + } + }; + + [TestCaseSource(nameof(TestCasesForKruskalsAlgorithm))] + public void TestKruskal_ShouldGetExpectedResult(int totalNodes, List> edges, int expected) + { + var result = Algorithms.Graph.KruskalsAlgorithm.KruskalDriver(totalNodes, edges); + var propertyInfo = result.GetType().GetProperty("weight"); + var weight = propertyInfo.GetValue(result, null); + + Assert.AreEqual(expected, weight); + } + } +}