Skip to content

Commit

Permalink
Merge pull request #5 from Timmoth/features/dfs
Browse files Browse the repository at this point in the history
Added DFS implementation
  • Loading branch information
Timmoth authored Dec 23, 2023
2 parents 1a013df + c358bc7 commit c7fb761
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 32 deletions.
31 changes: 31 additions & 0 deletions Benchmarks/Graphs/DfsBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using BenchmarkDotNet.Attributes;
using DsaDotnet.Graphs;

namespace Benchmarks.Graphs;

public class DfsBenchmarks
{
private static readonly RandomNetworkGenerator<int> _randomNetworkGenerator = new();
private Graph<int> _graph = null!;
[Params(100, 1000)] public int N { get; set; }

[IterationSetup]
public void Setup()
{
_graph = new Graph<int>();
_graph.AddNodes(_randomNetworkGenerator.GenerateRandomNetwork(N, n => n));
}

[Benchmark]
[BenchmarkCategory("Graph")]
public void Bfs()
{
_graph.DepthFirstSearch(0, i => i == N - 1);
}

[IterationCleanup]
public void Cleanup()
{
_graph = null!;
}
}
2 changes: 1 addition & 1 deletion DsaDotnet/DsaDotnet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

</Project>
</Project>
25 changes: 15 additions & 10 deletions DsaDotnet/Graphs/Bfs.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
namespace DsaDotnet.Graphs;

public static class Traversal
public static partial class Traversal
{
public static List<T>? BreadthFirstSearch<T>(this Graph<T> graph, T start, Predicate<T> predicate) where T : notnull
public static Node<T>? BreadthFirstSearch<T>(this Graph<T> graph, T start, Predicate<T> predicate) where T : notnull
{
if (!graph.Nodes.ContainsKey(start))
{
throw new ArgumentException("Start node does not exist in the graph.");
}

var result = new List<T>();

var visited = new HashSet<T>();
var queue = new Queue<Node<T>>();

queue.Enqueue(graph.Nodes[start]);
var startNode = graph.Nodes[start];
queue.Enqueue(startNode);
visited.Add(start);

if (predicate(startNode.Data))
{
return startNode;
}

while (queue.Count > 0)
{
var currentNode = queue.Dequeue();
result.Add(currentNode.Data);

if (predicate(currentNode.Data))
{
return result;
}

foreach (var neighbor in currentNode.Neighbors)
{
Expand All @@ -33,6 +33,11 @@ public static class Traversal
continue;
}

if (predicate(currentNode.Data))
{
return neighbor;
}

queue.Enqueue(neighbor);
visited.Add(neighbor.Data);
}
Expand Down
47 changes: 47 additions & 0 deletions DsaDotnet/Graphs/Dfs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace DsaDotnet.Graphs;

public static partial class Traversal
{
public static Node<T>? DepthFirstSearch<T>(this Graph<T> graph, T start, Predicate<T> predicate) where T : notnull
{
if (!graph.Nodes.ContainsKey(start))
{
throw new ArgumentException("Start node does not exist in the graph.");
}

var visited = new HashSet<T>();
var stack = new Stack<Node<T>>();

var startNode = graph.Nodes[start];
stack.Push(startNode);
visited.Add(start);

if (predicate(startNode.Data))
{
return startNode;
}

while (stack.Count > 0)
{
var currentNode = stack.Pop();

foreach (var neighbor in currentNode.Neighbors)
{
if (visited.Contains(neighbor.Data))
{
continue;
}

if (predicate(neighbor.Data))
{
return neighbor;
}

stack.Push(neighbor);
visited.Add(neighbor.Data);
}
}

return null;
}
}
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ To run the benchmarks for all sorting algorithms:

Usage
```cs
ulong result = Series.Factorial(1000)
ulong result = Series.Factorial(1000);
result = 1000.Factorial();
```
Benchmarks
Expand All @@ -58,7 +58,7 @@ dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --

Usage
```cs
ulong result = Series.Fibonacci(1000)
ulong result = Series.Fibonacci(1000);
result = 1000.Fibonacci();
```
Benchmarks
Expand All @@ -71,7 +71,7 @@ dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --

Usage
```cs
List<int> result = Series.PrimesUpTo(1000)
List<int> result = Series.PrimesUpTo(1000);
result = 1000.PrimesUpTo();
```
Benchmarks
Expand All @@ -92,13 +92,27 @@ Usage
```cs
var graph = new Graph<int>();
graph.AddEdges((0, 1), (1, 2), (2, 3));
var path = graph.BreadthFirstSearch(0, n => n == 3);
var node = graph.BreadthFirstSearch(0, n => n == 3);
```
Benchmarks
```
dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --memory --f *Bfs*
```

### Depth first search
---

Usage
```cs
var graph = new Graph<int>();
graph.AddEdges((0, 1), (1, 2), (2, 3));
var node = graph.DepthFirstSearch(0, n => n == 3);
```
Benchmarks
```
dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --memory --f *Dfs*
```

## Sorting

To run the benchmarks for all sorting algorithms:
Expand Down
13 changes: 0 additions & 13 deletions Tests/Graphs/BfsTestData.cs

This file was deleted.

9 changes: 5 additions & 4 deletions Tests/Graphs/BfsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ namespace Tests.Graphs;
public class BfsTests
{
[Theory]
[ClassData(typeof(BfsTestData))]
public void TestBfs((int a, int b)[] edges, Predicate<int> predicate, int start, int[]? expected)
[ClassData(typeof(GraphSearchTestData))]
public void Bfs_Finds_ShortestPath_From_Source_To_Destination((int a, int b)[] edges, Predicate<int> predicate,
int start, int? expected)
{
// Arrange
var graph = new Graph<int>();
graph.AddEdges(edges);

// Act
var bfsResult = graph.BreadthFirstSearch(start, predicate);
var node = graph.BreadthFirstSearch(start, predicate);

// Assert
bfsResult.Should().Equal(expected);
node?.Data.Should().Be(expected);
}
}
23 changes: 23 additions & 0 deletions Tests/Graphs/DfsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using DsaDotnet.Graphs;
using FluentAssertions;

namespace Tests.Graphs;

public class DfsTests
{
[Theory]
[ClassData(typeof(GraphSearchTestData))]
public void Dfs_Finds_ShortestPath_From_Source_To_Destination((int a, int b)[] edges, Predicate<int> predicate,
int start, int? expected)
{
// Arrange
var graph = new Graph<int>();
graph.AddEdges(edges);

// Act
var node = graph.DepthFirstSearch(start, predicate);

// Assert
node?.Data.Should().Be(expected);
}
}
14 changes: 14 additions & 0 deletions Tests/Graphs/GraphSearchTestData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Tests.Graphs;

public class GraphSearchTestData : TheoryData<(int a, int b)[], Predicate<int>, int, int?>
{
public GraphSearchTestData()
{
Add(new[] { (0, 1), (1, 2) }, i => i == 3, 0, null);
Add(new[] { (0, 1) }, i => i == 0, 0, 0);
Add(new[] { (0, 1), (1, 2), (2, 3) }, i => i == 3, 0, 3);
Add(new[] { (0, 1), (1, 2), (2, 3) }, i => i == 3, 2, 3);
Add(new[] { (0, 1), (0, 2), (1, 3), (2, 4), (3, 4) }, i => i == 4, 0, 4);
Add(new[] { (0, 1), (0, 2), (2, 1), (2, 2), (1, 3), (2, 4), (3, 4) }, i => i == 4, 0, 4);
}
}

0 comments on commit c7fb761

Please sign in to comment.