diff --git a/DIRECTORY.md b/DIRECTORY.md index a518232e9..12e22361d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -10,6 +10,14 @@ * [Rat Maze](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/rat_maze.cpp) * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) +## Computer Oriented Statistical Methods + * [Bisection Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/computer_oriented_statistical_methods/bisection_method.cpp) + * [False Position](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/computer_oriented_statistical_methods/false_position.cpp) + * [Gaussian Elimination](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/computer_oriented_statistical_methods/gaussian_elimination.cpp) + * [Newton Raphson Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/computer_oriented_statistical_methods/newton_raphson_method.cpp) + * [Ordinary Least Squares Regressor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/computer_oriented_statistical_methods/ordinary_least_squares_regressor.cpp) + * [Successive Approximation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/computer_oriented_statistical_methods/successive_approximation.cpp) + ## Data Structure * [Avltree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/avltree.cpp) * [Binary Search Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/binary_search_tree.cpp) @@ -40,7 +48,7 @@ * [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/stk/stack.cpp) * [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/stk/stack.h) * [Test Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/stk/test_stack.cpp) - * [Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/Tree.cpp) + * [Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/tree.cpp) * [Trie Modern](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/trie_modern.cpp) * [Trie Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/trie_tree.cpp) @@ -73,6 +81,7 @@ * [Bridge Finding With Tarjan Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/bridge_finding_with_tarjan_algorithm.cpp) * [Connected Components](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/connected_components.cpp) * [Connected Components With Dsu](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/connected_components_with_dsu.cpp) + * [Cycle Check Directed Graph](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/cycle_check_directed_graph.cpp) * [Dfs](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dfs.cpp) * [Dfs With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dfs_with_stack.cpp) * [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/dijkstra.cpp) @@ -99,7 +108,6 @@ ## Machine Learning * [Adaline Learning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/adaline_learning.cpp) - * [Kohonen Som Trace](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/kohonen_som_trace.cpp) ## Math * [Binary Exponent](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/binary_exponent.cpp) @@ -127,15 +135,6 @@ * [Sqrt Double](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sqrt_double.cpp) * [String Fibonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/string_fibonacci.cpp) -## Numerical Methods - * [Bisection Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/bisection_method.cpp) - * [Durand Kerner Roots](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/durand_kerner_roots.cpp) - * [False Position](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/false_position.cpp) - * [Gaussian Elimination](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/gaussian_elimination.cpp) - * [Newton Raphson Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/newton_raphson_method.cpp) - * [Ordinary Least Squares Regressor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ordinary_least_squares_regressor.cpp) - * [Successive Approximation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/successive_approximation.cpp) - ## Operations On Datastructures * [Array Left Rotation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/array_left_rotation.cpp) * [Array Right Rotation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/array_right_rotation.cpp) diff --git a/graph/cycle_check_directed_graph.cpp b/graph/cycle_check_directed_graph.cpp new file mode 100644 index 000000000..0f7b84cd3 --- /dev/null +++ b/graph/cycle_check_directed_graph.cpp @@ -0,0 +1,302 @@ +/** + * Copyright 2020 + * @file cycle_check_directed graph.cpp + * + * @brief BFS and DFS algorithms to check for cycle in a directed graph. + * + * @author Anmol3299 + * contact: mittalanmol22@gmail.com + * + */ + +#include // for std::cout +#include // for std::queue +#include // for throwing errors +#include // for std::remove_reference_t +#include // for std::unordered_map +#include // for std::move +#include // for std::vector + +/** + * Implementation of non-weighted directed edge of a graph. + * + * The source vertex of the edge is labelled "src" and destination vertex is + * labelled "dest". + */ +struct Edge { + unsigned int src; + unsigned int dest; + + Edge() = delete; + ~Edge() = default; + Edge(Edge&&) = default; + Edge& operator=(Edge&&) = default; + Edge(Edge const&) = default; + Edge& operator=(Edge const&) = default; + + /** Set the source and destination of the vertex. + * + * @param source is the source vertex of the edge. + * @param destination is the destination vertex of the edge. + */ + Edge(unsigned int source, unsigned int destination) + : src(source), dest(destination) {} +}; + +using AdjList = std::unordered_map>; + +/** + * Implementation of graph class. + * + * The graph will be represented using Adjacency List representation. + * This class contains 2 data members "m_vertices" & "m_adjList" used to + * represent the number of vertices and adjacency list of the graph + * respectively. The vertices are labelled 0 - (m_vertices - 1). + */ +class Graph { + public: + Graph() : m_vertices(0), m_adjList({}) {} + ~Graph() = default; + Graph(Graph&&) = default; + Graph& operator=(Graph&&) = default; + Graph(Graph const&) = default; + Graph& operator=(Graph const&) = default; + + /** Create a graph from vertices and adjacency list. + * + * @param vertices specify the number of vertices the graph would contain. + * @param adjList is the adjacency list representation of graph. + */ + Graph(unsigned int vertices, AdjList const& adjList) + : m_vertices(vertices), m_adjList(adjList) {} + + /** Create a graph from vertices and adjacency list. + * + * @param vertices specify the number of vertices the graph would contain. + * @param adjList is the adjacency list representation of graph. + */ + Graph(unsigned int vertices, AdjList&& adjList) + : m_vertices(std::move(vertices)), m_adjList(std::move(adjList)) {} + + /** Create a graph from vertices and a set of edges. + * + * Adjacency list of the graph would be created from the set of edges. If + * the source or destination of any edge has a value greater or equal to + * number of vertices, then it would throw a range_error. + * + * @param vertices specify the number of vertices the graph would contain. + * @param edges is a vector of edges. + */ + Graph(unsigned int vertices, std::vector const& edges) + : m_vertices(vertices) { + for (auto const& edge : edges) { + if (edge.src >= vertices || edge.dest >= vertices) { + throw std::range_error( + "Either src or dest of edge out of range"); + } + m_adjList[edge.src].emplace_back(edge.dest); + } + } + + /** Return a const reference of the adjacency list. + * + * @return const reference to the adjacency list + */ + std::remove_reference_t const& getAdjList() const { + return m_adjList; + } + + /** + * @return number of vertices in the graph. + */ + std::remove_reference_t const& getVertices() const { + return m_vertices; + } + + /** Add vertices in the graph. + * + * @param num is the number of vertices to be added. It adds 1 vertex by + * default. + * + */ + void addVertices(unsigned int num = 1) { m_vertices += num; } + + /** Add an edge in the graph. + * + * @param edge that needs to be added. + */ + void addEdge(Edge const& edge) { + if (edge.src >= m_vertices || edge.dest >= m_vertices) { + throw std::range_error("Either src or dest of edge out of range"); + } + m_adjList[edge.src].emplace_back(edge.dest); + } + + /** Add an Edge in the graph + * + * @param source is source vertex of the edge. + * @param destination is the destination vertex of the edge. + */ + void addEdge(unsigned int source, unsigned int destination) { + if (source >= m_vertices || destination >= m_vertices) { + throw std::range_error( + "Either source or destination of edge out of range"); + } + m_adjList[source].emplace_back(destination); + } + + private: + unsigned int m_vertices; + AdjList m_adjList; +}; + +class CycleCheck { + private: + enum nodeStates : uint8_t { not_visited = 0, in_stack, visited }; + + /** Helper function of "isCyclicDFS". + * + * @param adjList is the adjacency list representation of some graph. + * @param state is the state of the nodes of the graph. + * @param node is the node being evaluated. + * + * @return true if graph has a cycle, else false. + */ + static bool isCyclicDFSHelper(AdjList const& adjList, + std::vector* state, + unsigned int node) { + // Add node "in_stack" state. + (*state)[node] = in_stack; + + // If the node has children, then recursively visit all children of the + // node. + if (auto const& it = adjList.find(node); it != adjList.end()) { + for (auto child : it->second) { + // If state of child node is "not_visited", evaluate that child + // for presence of cycle. + if (auto state_of_child = (*state)[child]; + state_of_child == not_visited) { + if (isCyclicDFSHelper(adjList, state, child)) { + return true; + } + } else if (state_of_child == in_stack) { + // If child node was "in_stack", then that means that there + // is a cycle in the graph. Return true for presence of the + // cycle. + return true; + } + } + } + + // Current node has been evaluated for the presence of cycle and had no + // cycle. Mark current node as "visited". + (*state)[node] = visited; + // Return that current node didn't result in any cycles. + return false; + } + + public: + /** Driver function to check if a graph has a cycle. + * + * This function uses DFS to check for cycle in the graph. + * + * @param graph which needs to be evaluated for the presence of cycle. + * @return true if a cycle is detected, else false. + */ + static bool isCyclicDFS(Graph const& graph) { + /** State of the node. + * + * It is a vector of "nodeStates" which represents the state node is in. + * It can take only 3 values: "not_visited", "in_stack", and "visited". + * + * Initially, all nodes are in "not_visited" state. + */ + std::vector state(graph.getVertices(), not_visited); + + // Start visiting each node. + for (auto node = 0; node < graph.getVertices(); node++) { + // If a node is not visited, only then check for presence of cycle. + // There is no need to check for presence of cycle for a visited + // node as it has already been checked for presence of cycle. + if (state[node] == not_visited) { + // Check for cycle. + if (isCyclicDFSHelper(graph.getAdjList(), &state, node)) { + return true; + } + } + } + + // All nodes have been safely traversed, that means there is no cycle in + // the graph. Return false. + return false; + } + + /** Check if a graph has cycle or not. + * + * This function uses BFS to check if a graph is cyclic or not. + * + * @param graph which needs to be evaluated for the presence of cycle. + * @return true if a cycle is detected, else false. + */ + static bool isCyclicBFS(Graph const& graph) { + AdjList graphAjdList = graph.getAdjList(); + + std::vector indegree(graph.getVertices(), 0); + // Calculate the indegree i.e. the number of incident edges to the node. + for (auto const& [parent, children] : graphAjdList) { + for (auto const& child : children) { + indegree[child]++; + } + } + + std::queue can_be_solved; + for (auto node = 0; node < graph.getVertices(); node++) { + // If a node doesn't have any input edges, then that node will + // definately not result in a cycle and can be visited safely. + if (!indegree[node]) { + can_be_solved.emplace(node); + } + } + + // Vertices that need to be traversed. + auto remain = graph.getVertices(); + // While there are safe nodes that we can visit. + while (!can_be_solved.empty()) { + auto front = can_be_solved.front(); + // Visit the node. + can_be_solved.pop(); + // Decrease number of nodes that need to be traversed. + remain--; + + // Visit all the children of the visited node. + if (auto it = graphAjdList.find(front); it != graphAjdList.end()) { + for (auto child : it->second) { + // Check if we can visited the node safely. + if (--indegree[child] == 0) { + // if node can be visited safely, then add that node to + // the visit queue. + can_be_solved.emplace(child); + } + } + } + } + + // If there are still nodes that we can't visit, then it means that + // there is a cycle and return true, else return false. + return !(remain == 0); + } +}; + +/** + * Main function. + */ +int main() { + // Instantiate the graph. + Graph g(7, std::vector{{0, 1}, {1, 2}, {2, 0}, {2, 5}, {3, 5}}); + // Check for cycle using BFS method. + std::cout << CycleCheck::isCyclicBFS(g) << '\n'; + + // Check for cycle using DFS method. + std::cout << CycleCheck::isCyclicDFS(g) << '\n'; + return 0; +}