Skip to content

Commit 33c45f9

Browse files
authoredOct 14, 2020
Merge pull request #1179 from pranavkhapra/DepthFirstSearch
Depth first search
2 parents ccc21fa + c91b59d commit 33c45f9

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/***
2+
* Implements the Depth-First Search algorithm in two ways: Iterative and Recursive.
3+
*
4+
* Provides multiple functions for traversing graphs:
5+
* 1. PrintAll(),
6+
* 2. VisitAll(Action<T> forEachFunc),
7+
* 3. FindFirstMatch(Predicate<T> match).
8+
*
9+
* The VisitAll() applies a function to every graph node. The FindFirstMatch() function searches the graph for a predicate match.
10+
*/
11+
12+
using System;
13+
using System.Collections.Generic;
14+
15+
using DataStructures.Graphs;
16+
17+
namespace Algorithms.Graphs
18+
{
19+
public static class DepthFirstSearcher
20+
{
21+
/// <summary>
22+
/// DFS Recursive Helper function.
23+
/// Visits the neighbors of a given vertex recusively, and applies the given Action<T> to each one of them.
24+
/// </summary>
25+
private static void _visitNeighbors<T>(T Vertex, ref IGraph<T> Graph, ref Dictionary<T, object> Parents, Action<T> Action) where T : IComparable<T>
26+
{
27+
foreach (var adjacent in Graph.Neighbours(Vertex))
28+
{
29+
if (!Parents.ContainsKey(adjacent))
30+
{
31+
// DFS VISIT NODE
32+
Action(adjacent);
33+
34+
// Save adjacents parent into dictionary
35+
Parents.Add(adjacent, Vertex);
36+
37+
// Recusively visit adjacent nodes
38+
_visitNeighbors(adjacent, ref Graph, ref Parents, Action);
39+
}
40+
}
41+
}
42+
43+
/// <summary>
44+
/// Recursive DFS Implementation with helper.
45+
/// Traverses all the nodes in a graph starting from a specific node, applying the passed action to every node.
46+
/// </summary>
47+
public static void VisitAll<T>(ref IGraph<T> Graph, T StartVertex, Action<T> Action) where T : IComparable<T>
48+
{
49+
// Check if graph is empty
50+
if (Graph.VerticesCount == 0)
51+
throw new Exception("Graph is empty!");
52+
53+
// Check if graph has the starting vertex
54+
if (!Graph.HasVertex(StartVertex))
55+
throw new Exception("Starting vertex doesn't belong to graph.");
56+
57+
var parents = new Dictionary<T, object>(Graph.VerticesCount); // keeps track of visited nodes and tree-edges
58+
59+
foreach (var vertex in Graph.Neighbours(StartVertex))
60+
{
61+
if (!parents.ContainsKey(vertex))
62+
{
63+
// DFS VISIT NODE
64+
Action(vertex);
65+
66+
// Add to parents dictionary
67+
parents.Add(vertex, null);
68+
69+
// Visit neighbors using recusrive helper
70+
_visitNeighbors(vertex, ref Graph, ref parents, Action);
71+
}
72+
}
73+
}
74+
75+
/// <summary>
76+
/// Iterative DFS Implementation.
77+
/// Given a starting node, dfs the graph and print the nodes as they get visited.
78+
/// </summary>
79+
public static void PrintAll<T>(IGraph<T> Graph, T StartVertex) where T : IComparable<T>
80+
{
81+
// Check if graph is empty
82+
if (Graph.VerticesCount == 0)
83+
throw new Exception("Graph is empty!");
84+
85+
// Check if graph has the starting vertex
86+
if (!Graph.HasVertex(StartVertex))
87+
throw new Exception("Starting vertex doesn't belong to graph.");
88+
89+
var visited = new HashSet<T>();
90+
var stack = new Stack<T>(Graph.VerticesCount);
91+
92+
stack.Push(StartVertex);
93+
94+
while (stack.Count > 0)
95+
{
96+
var current = stack.Pop();
97+
98+
if (!visited.Contains(current))
99+
{
100+
// DFS VISIT NODE STEP
101+
Console.Write(String.Format("({0}) ", current));
102+
visited.Add(current);
103+
104+
// Get the adjacent nodes of current
105+
foreach (var adjacent in Graph.Neighbours(current))
106+
if (!visited.Contains(adjacent))
107+
stack.Push(adjacent);
108+
}
109+
}
110+
111+
}
112+
113+
/// <summary>
114+
/// Iterative DFS Implementation.
115+
/// Given a predicate function and a starting node, this function searches the nodes of the graph for a first match.
116+
/// </summary>
117+
public static T FindFirstMatch<T>(IGraph<T> Graph, T StartVertex, Predicate<T> Match) where T : IComparable<T>
118+
{
119+
// Check if graph is empty
120+
if (Graph.VerticesCount == 0)
121+
throw new Exception("Graph is empty!");
122+
123+
// Check if graph has the starting vertex
124+
if (!Graph.HasVertex(StartVertex))
125+
throw new Exception("Starting vertex doesn't belong to graph.");
126+
127+
var stack = new Stack<T>();
128+
var parents = new Dictionary<T, object>(Graph.VerticesCount); // keeps track of visited nodes and tree-edges
129+
130+
object currentParent = null;
131+
stack.Push(StartVertex);
132+
133+
while (stack.Count > 0)
134+
{
135+
var current = stack.Pop();
136+
137+
// Skip loop if node was already visited
138+
if (!parents.ContainsKey(current))
139+
{
140+
// Save its parent into the dictionary
141+
// Mark it as visited
142+
parents.Add(current, currentParent);
143+
144+
// DFS VISIT NODE STEP
145+
if (Match(current))
146+
return current;
147+
148+
// Get currents adjacent nodes (might add already visited nodes).
149+
foreach (var adjacent in Graph.Neighbours(current))
150+
if (!parents.ContainsKey(adjacent))
151+
stack.Push(adjacent);
152+
153+
// Mark current as the father of its adjacents. This helps keep track of tree-nodes.
154+
currentParent = current;
155+
}
156+
}//end-while
157+
158+
throw new Exception("Item was not found!");
159+
}
160+
161+
}
162+
163+
}
164+
165+
166+

0 commit comments

Comments
 (0)
Please sign in to comment.