From d057b243d9a1279243a7d7c3264b5ee36536a8c0 Mon Sep 17 00:00:00 2001 From: Waqar Hassan Khan Date: Mon, 6 Sep 2021 01:20:51 +0600 Subject: [PATCH] chore(CSharp): add Depth First Search (#447) --- algorithms/CSharp/README.md | 5 +- .../CSharp/src/Graph/depth-first-search.cs | 131 ++++++++++++++++++ .../CSharp/test/Graph/depth-first-search.cs | 64 +++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 algorithms/CSharp/src/Graph/depth-first-search.cs create mode 100644 algorithms/CSharp/test/Graph/depth-first-search.cs diff --git a/algorithms/CSharp/README.md b/algorithms/CSharp/README.md index 5430e572..040bd275 100644 --- a/algorithms/CSharp/README.md +++ b/algorithms/CSharp/README.md @@ -18,4 +18,7 @@ For running the `.cs` file please using [.Net Finddle](https://dotnetfiddle.net/ - [Abundant Number](src/Maths/abundant-number.cs) ## Recusrsion -- [Factorial](src/Recursion/factorial.cs) \ No newline at end of file +- [Factorial](src/Recursion/factorial.cs) + +## Graph +- [Depth First Search](src/Graph/depth-first-search.cs) \ No newline at end of file diff --git a/algorithms/CSharp/src/Graph/depth-first-search.cs b/algorithms/CSharp/src/Graph/depth-first-search.cs new file mode 100644 index 00000000..e7f7d3ca --- /dev/null +++ b/algorithms/CSharp/src/Graph/depth-first-search.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Algorithms.Graph +{ + public class DepthFirstSearch + { + class Graph + { + private int _vertex; + private bool _cycleFound; + private List> _adjacencyList; + private List _parent; + private List _visited; + private List _traversal; + + public const int WHITE = 0; + public const int GREY = 1; + public const int BLACK = 2; + + public Graph(int vertex) + { + _vertex = vertex; + _traversal = new List(); + _adjacencyList = new List>(vertex + 1); + + for (int i = 0; i <= vertex; i++) + { + _adjacencyList.Add(new List()); + } + } + + public void AddEdge(int start, int end) + { + _adjacencyList[start].Add(end); + } + + public List DFS(int source) + { + _parent = Enumerable.Repeat(-1, _vertex + 1).ToList(); + _visited = Enumerable.Repeat(WHITE, _vertex + 1).ToList(); + _traversal.Clear(); + + DFSRecursive(source); + return _traversal; + } + + + public bool HasCycle() + { + _parent = Enumerable.Repeat(-1, _vertex + 1).ToList(); + _visited = Enumerable.Repeat(WHITE, _vertex + 1).ToList(); + _traversal.Clear(); + + DFSRecursive(1); + return _cycleFound; + } + + private void DFSRecursive(int source) + { + _visited[source] = GREY; + _traversal.Add(source); + + foreach (int destination in _adjacencyList[source]) + { + if (_visited[destination] == WHITE) + { + _parent[destination] = source; + DFSRecursive(destination); + } + + else if (_visited[destination] == GREY && destination != _parent[source]) + { + _cycleFound = true; + } + } + + _visited[source] = BLACK; + } + + } + + + public static List DFS(int vertex, int src, List> edges) + { + Graph graph = new Graph(vertex); + foreach (var edge in edges) + { + graph.AddEdge(edge.Item1, edge.Item2); + graph.AddEdge(edge.Item2, edge.Item1); + } + + return graph.DFS(src); + } + + public static bool HasCycle(int vertex, List> edges) + { + Graph graph = new Graph(vertex); + foreach (var edge in edges) + { + graph.AddEdge(edge.Item1, edge.Item2); + graph.AddEdge(edge.Item2, edge.Item1); + } + + return graph.HasCycle(); + } + + public static void Main() + { + List> edges = new List>(); + edges.Add(new Tuple(1, 2)); + edges.Add(new Tuple(1, 3)); + edges.Add(new Tuple(4, 3)); + edges.Add(new Tuple(3, 5)); + + List traversal = DFS(5, 1, edges); + foreach (int v in traversal) + { + Console.Write($"{v} "); + } + + Console.WriteLine($"Has Cycle: {HasCycle(5, edges)}"); + } + } +} + +/* + * depth first search for an undirected graph + * also cycles are detected + */ \ No newline at end of file diff --git a/algorithms/CSharp/test/Graph/depth-first-search.cs b/algorithms/CSharp/test/Graph/depth-first-search.cs new file mode 100644 index 00000000..cb76eebd --- /dev/null +++ b/algorithms/CSharp/test/Graph/depth-first-search.cs @@ -0,0 +1,64 @@ +using System; +using NUnit.Framework; +using System.Collections.Generic; + +namespace Algorithms.Tests.Graph +{ + [TestFixture] + public class DepthFirstSearch + { + static object[] DivideCasesForDFS = + { + new object[] { 5, 3, new List> { + new Tuple(1, 2), + new Tuple(1, 3), + new Tuple(2, 3), + new Tuple(4, 2), + new Tuple(1, 5) + }, "3 1 2 4 5" + }, + new object[] { 5, 1, new List> { + new Tuple(1, 2), + new Tuple(1, 3), + new Tuple(4, 3), + new Tuple(3, 5) + }, "1 2 3 4 5" + } + }; + + static object[] DivideCasesForCycleDetection = + { + new object[] { 5, new List> { + new Tuple(1, 2), + new Tuple(1, 3), + new Tuple(2, 3), + new Tuple(4, 2), + new Tuple(1, 5) + }, true + }, + new object[] { 5, new List> { + new Tuple(1, 2), + new Tuple(1, 3), + new Tuple(4, 3), + new Tuple(3, 5) + }, false + } + }; + + + [TestCaseSource(nameof(DivideCasesForDFS))] + public void TestDFS_ShouldGetExpectedResult(int vertex, int source, List> edges, string expected) + { + List result = Algorithms.Graph.DepthFirstSearch.DFS(vertex, source, edges); + Assert.AreEqual(expected, string.Join(' ', result)); + } + + + [TestCaseSource(nameof(DivideCasesForCycleDetection))] + public void TestCycleDetection_ShouldGetExpectedResult(int vertex, List> edges, bool expected) + { + bool result = Algorithms.Graph.DepthFirstSearch.HasCycle(vertex, edges); + Assert.AreEqual(expected, result); + } + } +}