diff --git a/graph/depth_first_search_with_stack.cpp b/graph/depth_first_search_with_stack.cpp index 9810edeb1..5376ea4c4 100644 --- a/graph/depth_first_search_with_stack.cpp +++ b/graph/depth_first_search_with_stack.cpp @@ -1,46 +1,207 @@ -#include -#include -#include -#include +/** + * + * @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. + * + *

Working

+ * 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. + */ -constexpr int WHITE = 0; -constexpr int GREY = 1; -constexpr int BLACK = 2; -constexpr int INF = 99999; +#include /// for IO operations +#include /// header for std::stack +#include /// header for std::vector +#include /// header for preprocessor macro assert() +#include /// 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::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> *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 dfs(const std::vector > &graph, size_t start) { + /// checked[i] stores the status of each node + std::vector checked(graph.size(), WHITE), traversed_path; -void dfs(const std::vector > &graph, int start) { - std::vector checked(graph.size(), WHITE); checked[start] = GREY; - std::stack stack; + std::stack 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) { - std::cout << act << ' '; + /// 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; // nodo controllato + 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 > g1(3, std::vector()); + + 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 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 > g2(4, std::vector()); + + 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 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 > g3(4, std::vector()); + + 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 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() { - int n = 0; - std::cin >> n; - std::vector > graph(INF); - for (int i = 0; i < n; ++i) { - int u = 0, w = 0; - std::cin >> u >> w; - graph[u].push_back(w); - } + tests(); // execute the tests - dfs(graph, 0); + size_t vertices = 0, edges = 0, start_pos = 1; + std::vector traversal; + + std::cout << "Enter the Vertices : "; + std::cin >> vertices; + std::cout << "Enter the Edges : "; + std::cin >> edges; + + /// creating a graph + std::vector > adj(vertices, std::vector()); + + /// 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; }