TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
cycle_check_directed_graph.cpp
1
10#include <cstdint>
11#include <iostream> // for std::cout
12#include <map> // for std::map
13#include <queue> // for std::queue
14#include <stdexcept> // for throwing errors
15#include <type_traits> // for std::remove_reference
16#include <utility> // for std::move
17#include <vector> // for std::vector
18
25struct Edge {
26 unsigned int src;
27 unsigned int dest;
28
29 Edge() = delete;
30 ~Edge() = default;
31 Edge(Edge&&) = default;
32 Edge& operator=(Edge&&) = default;
33 Edge(Edge const&) = default;
34 Edge& operator=(Edge const&) = default;
35
41 Edge(unsigned int source, unsigned int destination)
42 : src(source), dest(destination) {}
43};
44
45using AdjList = std::map<unsigned int, std::vector<unsigned int>>;
46
55class Graph {
56 public:
57 Graph() : m_adjList({}) {}
58 ~Graph() = default;
59 Graph(Graph&&) = default;
60 Graph& operator=(Graph&&) = default;
61 Graph(Graph const&) = default;
62 Graph& operator=(Graph const&) = default;
63
69 Graph(unsigned int vertices, AdjList adjList)
70 : m_vertices(vertices), m_adjList(std::move(adjList)) {}
71
77 Graph(unsigned int vertices, AdjList&& adjList)
78 : m_vertices(vertices), m_adjList(std::move(adjList)) {}
79
89 Graph(unsigned int vertices, std::vector<Edge> const& edges)
90 : m_vertices(vertices) {
91 for (auto const& edge : edges) {
92 if (edge.src >= vertices || edge.dest >= vertices) {
93 throw std::range_error(
94 "Either src or dest of edge out of range");
95 }
96 m_adjList[edge.src].emplace_back(edge.dest);
97 }
98 }
99
104 std::remove_reference<AdjList>::type const& getAdjList() const {
105 return m_adjList;
106 }
107
111 unsigned int getVertices() const { return m_vertices; }
112
119 void addVertices(unsigned int num = 1) { m_vertices += num; }
120
125 void addEdge(Edge const& edge) {
126 if (edge.src >= m_vertices || edge.dest >= m_vertices) {
127 throw std::range_error("Either src or dest of edge out of range");
128 }
129 m_adjList[edge.src].emplace_back(edge.dest);
130 }
131
137 void addEdge(unsigned int source, unsigned int destination) {
138 if (source >= m_vertices || destination >= m_vertices) {
139 throw std::range_error(
140 "Either source or destination of edge out of range");
141 }
142 m_adjList[source].emplace_back(destination);
143 }
144
145 private:
146 unsigned int m_vertices = 0;
147 AdjList m_adjList;
148};
149
160 private:
161 enum nodeStates : uint8_t { not_visited = 0, in_stack, visited };
162
171 static bool isCyclicDFSHelper(AdjList const& adjList,
172 std::vector<nodeStates>* state,
173 unsigned int node) {
174 // Add node "in_stack" state.
175 (*state)[node] = in_stack;
176
177 // If the node has children, then recursively visit all children of the
178 // node.
179 auto const it = adjList.find(node);
180 if (it != adjList.end()) {
181 for (auto child : it->second) {
182 // If state of child node is "not_visited", evaluate that child
183 // for presence of cycle.
184 auto state_of_child = (*state)[child];
185 if (state_of_child == not_visited) {
186 if (isCyclicDFSHelper(adjList, state, child)) {
187 return true;
188 }
189 } else if (state_of_child == in_stack) {
190 // If child node was "in_stack", then that means that there
191 // is a cycle in the graph. Return true for presence of the
192 // cycle.
193 return true;
194 }
195 }
196 }
197
198 // Current node has been evaluated for the presence of cycle and had no
199 // cycle. Mark current node as "visited".
200 (*state)[node] = visited;
201 // Return that current node didn't result in any cycles.
202 return false;
203 }
204
205 public:
213 static bool isCyclicDFS(Graph const& graph) {
214 auto vertices = graph.getVertices();
215
223 std::vector<nodeStates> state(vertices, not_visited);
224
225 // Start visiting each node.
226 for (unsigned int node = 0; node < vertices; node++) {
227 // If a node is not visited, only then check for presence of cycle.
228 // There is no need to check for presence of cycle for a visited
229 // node as it has already been checked for presence of cycle.
230 if (state[node] == not_visited) {
231 // Check for cycle.
232 if (isCyclicDFSHelper(graph.getAdjList(), &state, node)) {
233 return true;
234 }
235 }
236 }
237
238 // All nodes have been safely traversed, that means there is no cycle in
239 // the graph. Return false.
240 return false;
241 }
242
250 static bool isCyclicBFS(Graph const& graph) {
251 auto graphAjdList = graph.getAdjList();
252 auto vertices = graph.getVertices();
253
254 std::vector<unsigned int> indegree(vertices, 0);
255 // Calculate the indegree i.e. the number of incident edges to the node.
256 for (auto const& list : graphAjdList) {
257 auto children = list.second;
258 for (auto const& child : children) {
259 indegree[child]++;
260 }
261 }
262
263 std::queue<unsigned int> can_be_solved;
264 for (unsigned int node = 0; node < vertices; node++) {
265 // If a node doesn't have any input edges, then that node will
266 // definately not result in a cycle and can be visited safely.
267 if (!indegree[node]) {
268 can_be_solved.emplace(node);
269 }
270 }
271
272 // Vertices that need to be traversed.
273 auto remain = vertices;
274 // While there are safe nodes that we can visit.
275 while (!can_be_solved.empty()) {
276 auto solved = can_be_solved.front();
277 // Visit the node.
278 can_be_solved.pop();
279 // Decrease number of nodes that need to be traversed.
280 remain--;
281
282 // Visit all the children of the visited node.
283 auto it = graphAjdList.find(solved);
284 if (it != graphAjdList.end()) {
285 for (auto child : it->second) {
286 // Check if we can visited the node safely.
287 if (--indegree[child] == 0) {
288 // if node can be visited safely, then add that node to
289 // the visit queue.
290 can_be_solved.emplace(child);
291 }
292 }
293 }
294 }
295
296 // If there are still nodes that we can't visit, then it means that
297 // there is a cycle and return true, else return false.
298 return !(remain == 0);
299 }
300};
301
305int main() {
306 // Instantiate the graph.
307 Graph g(7, std::vector<Edge>{{0, 1}, {1, 2}, {2, 0}, {2, 5}, {3, 5}});
308 // Check for cycle using BFS method.
309 std::cout << CycleCheck::isCyclicBFS(g) << '\n';
310
311 // Check for cycle using DFS method.
312 std::cout << CycleCheck::isCyclicDFS(g) << '\n';
313 return 0;
314}
struct node { int data; int height; struct node *left; struct node *right;} node
for std::queue
Definition avltree.cpp:13
static bool isCyclicDFSHelper(AdjList const &adjList, std::vector< nodeStates > *state, unsigned int node)
static bool isCyclicBFS(Graph const &graph)
static bool isCyclicDFS(Graph const &graph)
Edge(unsigned int source, unsigned int destination)
std::remove_reference< AdjList >::type const & getAdjList() const
Graph(unsigned int vertices, AdjList &&adjList)
unsigned int getVertices() const
Graph(unsigned int vertices, std::vector< Edge > const &edges)
void addVertices(unsigned int num=1)
void addEdge(unsigned int source, unsigned int destination)
Graph(unsigned int vertices, AdjList adjList)
void addEdge(Edge const &edge)
double g(double x)
Another test function.
int main()
Main function.
Graph Algorithms.