chore(CSharp): add Depth First Search (#447)
parent
f81fabe653
commit
d057b243d9
|
@ -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)
|
||||
- [Factorial](src/Recursion/factorial.cs)
|
||||
|
||||
## Graph
|
||||
- [Depth First Search](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<List<int>> _adjacencyList;
|
||||
private List<int> _parent;
|
||||
private List<int> _visited;
|
||||
private List<int> _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<int>();
|
||||
_adjacencyList = new List<List<int>>(vertex + 1);
|
||||
|
||||
for (int i = 0; i <= vertex; i++)
|
||||
{
|
||||
_adjacencyList.Add(new List<int>());
|
||||
}
|
||||
}
|
||||
|
||||
public void AddEdge(int start, int end)
|
||||
{
|
||||
_adjacencyList[start].Add(end);
|
||||
}
|
||||
|
||||
public List<int> 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<int> DFS(int vertex, int src, List<Tuple<int, int>> 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<Tuple<int, int>> 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<Tuple<int, int>> edges = new List<Tuple<int, int>>();
|
||||
edges.Add(new Tuple<int, int>(1, 2));
|
||||
edges.Add(new Tuple<int, int>(1, 3));
|
||||
edges.Add(new Tuple<int, int>(4, 3));
|
||||
edges.Add(new Tuple<int, int>(3, 5));
|
||||
|
||||
List<int> 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
|
||||
*/
|
|
@ -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<Tuple<int, int>> {
|
||||
new Tuple<int, int>(1, 2),
|
||||
new Tuple<int, int>(1, 3),
|
||||
new Tuple<int, int>(2, 3),
|
||||
new Tuple<int, int>(4, 2),
|
||||
new Tuple<int, int>(1, 5)
|
||||
}, "3 1 2 4 5"
|
||||
},
|
||||
new object[] { 5, 1, new List<Tuple<int, int>> {
|
||||
new Tuple<int, int>(1, 2),
|
||||
new Tuple<int, int>(1, 3),
|
||||
new Tuple<int, int>(4, 3),
|
||||
new Tuple<int, int>(3, 5)
|
||||
}, "1 2 3 4 5"
|
||||
}
|
||||
};
|
||||
|
||||
static object[] DivideCasesForCycleDetection =
|
||||
{
|
||||
new object[] { 5, new List<Tuple<int, int>> {
|
||||
new Tuple<int, int>(1, 2),
|
||||
new Tuple<int, int>(1, 3),
|
||||
new Tuple<int, int>(2, 3),
|
||||
new Tuple<int, int>(4, 2),
|
||||
new Tuple<int, int>(1, 5)
|
||||
}, true
|
||||
},
|
||||
new object[] { 5, new List<Tuple<int, int>> {
|
||||
new Tuple<int, int>(1, 2),
|
||||
new Tuple<int, int>(1, 3),
|
||||
new Tuple<int, int>(4, 3),
|
||||
new Tuple<int, int>(3, 5)
|
||||
}, false
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
[TestCaseSource(nameof(DivideCasesForDFS))]
|
||||
public void TestDFS_ShouldGetExpectedResult(int vertex, int source, List<Tuple<int, int>> edges, string expected)
|
||||
{
|
||||
List<int> result = Algorithms.Graph.DepthFirstSearch.DFS(vertex, source, edges);
|
||||
Assert.AreEqual(expected, string.Join(' ', result));
|
||||
}
|
||||
|
||||
|
||||
[TestCaseSource(nameof(DivideCasesForCycleDetection))]
|
||||
public void TestCycleDetection_ShouldGetExpectedResult(int vertex, List<Tuple<int, int>> edges, bool expected)
|
||||
{
|
||||
bool result = Algorithms.Graph.DepthFirstSearch.HasCycle(vertex, edges);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue