-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
depth_first_search_with_stack.cpp
207 lines (179 loc) · 6.31 KB
/
depth_first_search_with_stack.cpp
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/**
*
* @file
* @brief [Depth First Search Algorithm using Stack
* (Depth First Search Algorithm)](https://en.wikipedia.org/wiki/Depth-first_search)
*
* @author [Ayaan Khan](http://github.com/ayaankhan98)
* @author [Saurav Uppoor](https://github.com/sauravUppoor)
*
* @details
* Depth First Search also quoted as DFS is a Graph Traversal Algorithm.
* Time Complexity O(|V| + |E|) where V is number of vertices and E
* is number of edges in graph.
*
* Application of Depth First Search are
*
* 1. Finding connected components
* 2. Finding 2-(edge or vertex)-connected components.
* 3. Finding 3-(edge or vertex)-connected components.
* 4. Finding the bridges of a graph.
* 5. Generating words in order to plot the limit set of a group.
* 6. Finding strongly connected components.
*
* <h4>Working</h4>
* 1. Mark all vertices as unvisited (colour it WHITE).
* 2. Push starting vertex into the stack and colour it GREY.
* 3. Once a node is popped out of the stack and is coloured GREY, we colour it BLACK.
* 4. Push all its neighbours which are not coloured BLACK.
* 5. Repeat steps 4 and 5 until the stack is empty.
*/
#include <iostream> /// for IO operations
#include <stack> /// header for std::stack
#include <vector> /// header for std::vector
#include <cassert> /// header for preprocessor macro assert()
#include <limits> /// header for limits of integral types
constexpr int WHITE = 0; /// indicates the node hasn't been explored
constexpr int GREY = 1; /// indicates node is in stack waiting to be explored
constexpr int BLACK = 2; /// indicates node has already been explored
constexpr int64_t INF = std::numeric_limits<int16_t>::max();
/**
* @namespace graph
* @brief Graph algorithms
*/
namespace graph {
/**
* @namespace depth_first_search
* @brief Functions for [Depth First Search](https://en.wikipedia.org/wiki/Depth-first_search) algorithm
*/
namespace depth_first_search {
/**
* @brief
* Adds and edge between two vertices of graph say u and v in this
* case.
*
* @param adj Adjacency list representation of graph
* @param u first vertex
* @param v second vertex
*
*/
void addEdge(std::vector<std::vector<size_t>> *adj, size_t u, size_t v) {
/*
*
* Here we are considering undirected graph that's the
* reason we are adding v to the adjacency list representation of u
* and also adding u to the adjacency list representation of v
*
*/
(*adj)[u - 1].push_back(v - 1);
}
/**
*
* @brief
* Explores the given vertex, exploring a vertex means traversing
* over all the vertices which are connected to the vertex that is
* currently being explored and push it onto the stack.
*
* @param adj graph
* @param start starting vertex for DFS
* @return vector with nodes stored in the order of DFS traversal
*
*/
std::vector<size_t> dfs(const std::vector<std::vector<size_t> > &graph, size_t start) {
/// checked[i] stores the status of each node
std::vector<size_t> checked(graph.size(), WHITE), traversed_path;
checked[start] = GREY;
std::stack<size_t> stack;
stack.push(start);
/// while stack is not empty we keep exploring the node on top of stack
while (!stack.empty()) {
int act = stack.top();
stack.pop();
if (checked[act] == GREY) {
/// push the node to the final result vector
traversed_path.push_back(act + 1);
/// exploring the neighbours of the current node
for (auto it : graph[act]) {
stack.push(it);
if (checked[it] != BLACK) {
checked[it] = GREY;
}
}
checked[act] = BLACK; /// Node has been explored
}
}
return traversed_path;
}
} // namespace depth_first_search
} // namespace graph
/**
* Self-test implementations
* @returns none
*/
static void tests() {
size_t start_pos;
/// Test 1
std::cout << "Case 1: " << std::endl;
start_pos = 1;
std::vector<std::vector<size_t> > g1(3, std::vector<size_t>());
graph::depth_first_search::addEdge(&g1, 1, 2);
graph::depth_first_search::addEdge(&g1, 2, 3);
graph::depth_first_search::addEdge(&g1, 3, 1);
std::vector<size_t> expected1 {1, 2, 3}; /// for the above sample data, this is the expected output
assert(graph::depth_first_search::dfs(g1, start_pos - 1) == expected1);
std::cout << "Passed" << std::endl;
/// Test 2
std::cout << "Case 2: " << std::endl;
start_pos = 1;
std::vector<std::vector<size_t> > g2(4, std::vector<size_t>());
graph::depth_first_search::addEdge(&g2, 1, 2);
graph::depth_first_search::addEdge(&g2, 1, 3);
graph::depth_first_search::addEdge(&g2, 2, 4);
graph::depth_first_search::addEdge(&g2, 4, 1);
std::vector<size_t> expected2 {1, 3, 2, 4}; /// for the above sample data, this is the expected output
assert(graph::depth_first_search::dfs(g2, start_pos - 1) == expected2);
std::cout << "Passed" << std::endl;
/// Test 3
std::cout << "Case 3: " << std::endl;
start_pos = 2;
std::vector<std::vector<size_t> > g3(4, std::vector<size_t>());
graph::depth_first_search::addEdge(&g3, 1, 2);
graph::depth_first_search::addEdge(&g3, 1, 3);
graph::depth_first_search::addEdge(&g3, 2, 4);
graph::depth_first_search::addEdge(&g3, 4, 1);
std::vector<size_t> expected3 {2, 4, 1, 3}; /// for the above sample data, this is the expected output
assert(graph::depth_first_search::dfs(g3, start_pos - 1) == expected3);
std::cout << "Passed" << std::endl;
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
tests(); // execute the tests
size_t vertices = 0, edges = 0, start_pos = 1;
std::vector<size_t> traversal;
std::cout << "Enter the Vertices : ";
std::cin >> vertices;
std::cout << "Enter the Edges : ";
std::cin >> edges;
/// creating a graph
std::vector<std::vector<size_t> > adj(vertices, std::vector<size_t>());
/// taking input for the edges
std::cout << "Enter the vertices which have edges between them : " << std::endl;
while (edges--) {
size_t u = 0, v = 0;
std::cin >> u >> v;
graph::depth_first_search::addEdge(&adj, u, v);
}
/// taking input for the starting position
std::cout << "Enter the starting vertex [1,n]: " << std::endl;
std::cin >> start_pos;
start_pos -= 1;
traversal = graph::depth_first_search::dfs(adj, start_pos);
/// Printing the order of traversal
for (auto x : traversal) {
std::cout << x << ' ';
}
return 0;
}