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