Skip to content

Commit c7fb761

Browse files
authored
Merge pull request #5 from Timmoth/features/dfs
Added DFS implementation
2 parents 1a013df + c358bc7 commit c7fb761

File tree

9 files changed

+154
-32
lines changed

9 files changed

+154
-32
lines changed

Benchmarks/Graphs/DfsBenchmarks.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using BenchmarkDotNet.Attributes;
2+
using DsaDotnet.Graphs;
3+
4+
namespace Benchmarks.Graphs;
5+
6+
public class DfsBenchmarks
7+
{
8+
private static readonly RandomNetworkGenerator<int> _randomNetworkGenerator = new();
9+
private Graph<int> _graph = null!;
10+
[Params(100, 1000)] public int N { get; set; }
11+
12+
[IterationSetup]
13+
public void Setup()
14+
{
15+
_graph = new Graph<int>();
16+
_graph.AddNodes(_randomNetworkGenerator.GenerateRandomNetwork(N, n => n));
17+
}
18+
19+
[Benchmark]
20+
[BenchmarkCategory("Graph")]
21+
public void Bfs()
22+
{
23+
_graph.DepthFirstSearch(0, i => i == N - 1);
24+
}
25+
26+
[IterationCleanup]
27+
public void Cleanup()
28+
{
29+
_graph = null!;
30+
}
31+
}

DsaDotnet/DsaDotnet.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1414
</PropertyGroup>
1515

16-
</Project>
16+
</Project>

DsaDotnet/Graphs/Bfs.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
namespace DsaDotnet.Graphs;
22

3-
public static class Traversal
3+
public static partial class Traversal
44
{
5-
public static List<T>? BreadthFirstSearch<T>(this Graph<T> graph, T start, Predicate<T> predicate) where T : notnull
5+
public static Node<T>? BreadthFirstSearch<T>(this Graph<T> graph, T start, Predicate<T> predicate) where T : notnull
66
{
77
if (!graph.Nodes.ContainsKey(start))
88
{
99
throw new ArgumentException("Start node does not exist in the graph.");
1010
}
1111

12-
var result = new List<T>();
12+
1313
var visited = new HashSet<T>();
1414
var queue = new Queue<Node<T>>();
1515

16-
queue.Enqueue(graph.Nodes[start]);
16+
var startNode = graph.Nodes[start];
17+
queue.Enqueue(startNode);
1718
visited.Add(start);
1819

20+
if (predicate(startNode.Data))
21+
{
22+
return startNode;
23+
}
24+
1925
while (queue.Count > 0)
2026
{
2127
var currentNode = queue.Dequeue();
22-
result.Add(currentNode.Data);
23-
24-
if (predicate(currentNode.Data))
25-
{
26-
return result;
27-
}
2828

2929
foreach (var neighbor in currentNode.Neighbors)
3030
{
@@ -33,6 +33,11 @@ public static class Traversal
3333
continue;
3434
}
3535

36+
if (predicate(currentNode.Data))
37+
{
38+
return neighbor;
39+
}
40+
3641
queue.Enqueue(neighbor);
3742
visited.Add(neighbor.Data);
3843
}

DsaDotnet/Graphs/Dfs.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
namespace DsaDotnet.Graphs;
2+
3+
public static partial class Traversal
4+
{
5+
public static Node<T>? DepthFirstSearch<T>(this Graph<T> graph, T start, Predicate<T> predicate) where T : notnull
6+
{
7+
if (!graph.Nodes.ContainsKey(start))
8+
{
9+
throw new ArgumentException("Start node does not exist in the graph.");
10+
}
11+
12+
var visited = new HashSet<T>();
13+
var stack = new Stack<Node<T>>();
14+
15+
var startNode = graph.Nodes[start];
16+
stack.Push(startNode);
17+
visited.Add(start);
18+
19+
if (predicate(startNode.Data))
20+
{
21+
return startNode;
22+
}
23+
24+
while (stack.Count > 0)
25+
{
26+
var currentNode = stack.Pop();
27+
28+
foreach (var neighbor in currentNode.Neighbors)
29+
{
30+
if (visited.Contains(neighbor.Data))
31+
{
32+
continue;
33+
}
34+
35+
if (predicate(neighbor.Data))
36+
{
37+
return neighbor;
38+
}
39+
40+
stack.Push(neighbor);
41+
visited.Add(neighbor.Data);
42+
}
43+
}
44+
45+
return null;
46+
}
47+
}

README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ To run the benchmarks for all sorting algorithms:
4545

4646
Usage
4747
```cs
48-
ulong result = Series.Factorial(1000)
48+
ulong result = Series.Factorial(1000);
4949
result = 1000.Factorial();
5050
```
5151
Benchmarks
@@ -58,7 +58,7 @@ dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --
5858

5959
Usage
6060
```cs
61-
ulong result = Series.Fibonacci(1000)
61+
ulong result = Series.Fibonacci(1000);
6262
result = 1000.Fibonacci();
6363
```
6464
Benchmarks
@@ -71,7 +71,7 @@ dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --
7171

7272
Usage
7373
```cs
74-
List<int> result = Series.PrimesUpTo(1000)
74+
List<int> result = Series.PrimesUpTo(1000);
7575
result = 1000.PrimesUpTo();
7676
```
7777
Benchmarks
@@ -92,13 +92,27 @@ Usage
9292
```cs
9393
var graph = new Graph<int>();
9494
graph.AddEdges((0, 1), (1, 2), (2, 3));
95-
var path = graph.BreadthFirstSearch(0, n => n == 3);
95+
var node = graph.BreadthFirstSearch(0, n => n == 3);
9696
```
9797
Benchmarks
9898
```
9999
dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --memory --f *Bfs*
100100
```
101101

102+
### Depth first search
103+
---
104+
105+
Usage
106+
```cs
107+
var graph = new Graph<int>();
108+
graph.AddEdges((0, 1), (1, 2), (2, 3));
109+
var node = graph.DepthFirstSearch(0, n => n == 3);
110+
```
111+
Benchmarks
112+
```
113+
dotnet run --project ./Benchmarks/Benchmarks.csproj -c Release -- --job short --memory --f *Dfs*
114+
```
115+
102116
## Sorting
103117

104118
To run the benchmarks for all sorting algorithms:

Tests/Graphs/BfsTestData.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

Tests/Graphs/BfsTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ namespace Tests.Graphs;
66
public class BfsTests
77
{
88
[Theory]
9-
[ClassData(typeof(BfsTestData))]
10-
public void TestBfs((int a, int b)[] edges, Predicate<int> predicate, int start, int[]? expected)
9+
[ClassData(typeof(GraphSearchTestData))]
10+
public void Bfs_Finds_ShortestPath_From_Source_To_Destination((int a, int b)[] edges, Predicate<int> predicate,
11+
int start, int? expected)
1112
{
1213
// Arrange
1314
var graph = new Graph<int>();
1415
graph.AddEdges(edges);
1516

1617
// Act
17-
var bfsResult = graph.BreadthFirstSearch(start, predicate);
18+
var node = graph.BreadthFirstSearch(start, predicate);
1819

1920
// Assert
20-
bfsResult.Should().Equal(expected);
21+
node?.Data.Should().Be(expected);
2122
}
2223
}

Tests/Graphs/DfsTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using DsaDotnet.Graphs;
2+
using FluentAssertions;
3+
4+
namespace Tests.Graphs;
5+
6+
public class DfsTests
7+
{
8+
[Theory]
9+
[ClassData(typeof(GraphSearchTestData))]
10+
public void Dfs_Finds_ShortestPath_From_Source_To_Destination((int a, int b)[] edges, Predicate<int> predicate,
11+
int start, int? expected)
12+
{
13+
// Arrange
14+
var graph = new Graph<int>();
15+
graph.AddEdges(edges);
16+
17+
// Act
18+
var node = graph.DepthFirstSearch(start, predicate);
19+
20+
// Assert
21+
node?.Data.Should().Be(expected);
22+
}
23+
}

Tests/Graphs/GraphSearchTestData.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Tests.Graphs;
2+
3+
public class GraphSearchTestData : TheoryData<(int a, int b)[], Predicate<int>, int, int?>
4+
{
5+
public GraphSearchTestData()
6+
{
7+
Add(new[] { (0, 1), (1, 2) }, i => i == 3, 0, null);
8+
Add(new[] { (0, 1) }, i => i == 0, 0, 0);
9+
Add(new[] { (0, 1), (1, 2), (2, 3) }, i => i == 3, 0, 3);
10+
Add(new[] { (0, 1), (1, 2), (2, 3) }, i => i == 3, 2, 3);
11+
Add(new[] { (0, 1), (0, 2), (1, 3), (2, 4), (3, 4) }, i => i == 4, 0, 4);
12+
Add(new[] { (0, 1), (0, 2), (2, 1), (2, 2), (1, 3), (2, 4), (3, 4) }, i => i == 4, 0, 4);
13+
}
14+
}

0 commit comments

Comments
 (0)