@@ -517,6 +517,16 @@ namespace CXXGRAPH
517517 * @return true if a cycle is detected, else false. ( false is returned also if the graph in indirected)
518518 */
519519 const bool isCyclicDirectedGraphDFS () const ;
520+
521+ /* *
522+ * \brief
523+ * This function uses BFS to check for cycle in the graph.
524+ * Pay Attention, this function work only with directed Graph
525+ *
526+ * @return true if a cycle is detected, else false. ( false is returned also if the graph in indirected)
527+ */
528+ const bool isCyclicDirectedGraphBFS () const ;
529+
520530 /* *
521531 * \brief
522532 * This function checks if a graph is directed
@@ -807,7 +817,8 @@ namespace CXXGRAPH
807817 template <typename T>
808818 const bool Graph<T>::isCyclicDirectedGraphDFS() const
809819 {
810- if (!isDirectedGraph ()){
820+ if (!isDirectedGraph ())
821+ {
811822 return false ;
812823 }
813824 enum nodeStates : uint8_t
@@ -826,8 +837,9 @@ namespace CXXGRAPH
826837 *
827838 * Initially, all nodes are in "not_visited" state.
828839 */
829- std::map<unsigned long ,nodeStates> state;
830- for (auto node : nodeSet){
840+ std::map<unsigned long , nodeStates> state;
841+ for (auto node : nodeSet)
842+ {
831843 state[node->getId ()] = not_visited;
832844 }
833845 int stateCounter = 0 ;
@@ -841,8 +853,8 @@ namespace CXXGRAPH
841853 if (state[node->getId ()] == not_visited)
842854 {
843855 // Check for cycle.
844- std::function<bool (AdjacencyMatrix<T>&, std::map<unsigned long ,nodeStates>&, const Node<T>*)> isCyclicDFSHelper;
845- isCyclicDFSHelper = [this , &isCyclicDFSHelper](AdjacencyMatrix<T>& adjMatrix, std::map<unsigned long ,nodeStates>& states, const Node<T>* node)
856+ std::function<bool (AdjacencyMatrix<T> &, std::map<unsigned long , nodeStates> &, const Node<T> *)> isCyclicDFSHelper;
857+ isCyclicDFSHelper = [this , &isCyclicDFSHelper](AdjacencyMatrix<T> & adjMatrix, std::map<unsigned long , nodeStates> & states, const Node<T> * node)
846858 {
847859 // Add node "in_stack" state.
848860 states[node->getId ()] = in_stack;
@@ -891,13 +903,84 @@ namespace CXXGRAPH
891903 // the graph. Return false.
892904 return false ;
893905 }
894-
895- template <typename T>
906+
907+ template <typename T>
908+ const bool Graph<T>::isCyclicDirectedGraphBFS() const
909+ {
910+ if (!isDirectedGraph ())
911+ {
912+ return false ;
913+ }
914+ auto adjMatrix = this ->getAdjMatrix ();
915+ auto nodeSet = this ->getNodeSet ();
916+
917+ std::map<unsigned long , unsigned int > indegree;
918+ for (auto node : nodeSet)
919+ {
920+ indegree[node->getId ()] = 0 ;
921+ }
922+ // Calculate the indegree i.e. the number of incident edges to the node.
923+ for (auto const &list : adjMatrix)
924+ {
925+ auto children = list.second ;
926+ for (auto const &child : children)
927+ {
928+ indegree[std::get<0 >(child)->getId ()]++;
929+ }
930+ }
931+
932+ std::queue<const Node<T> *> can_be_solved;
933+ for (auto node : nodeSet)
934+ {
935+ // If a node doesn't have any input edges, then that node will
936+ // definately not result in a cycle and can be visited safely.
937+ if (!indegree[node->getId ()])
938+ {
939+ can_be_solved.emplace (&(*node));
940+ }
941+ }
942+
943+ // Vertices that need to be traversed.
944+ auto remain = this ->getNodeSet ().size ();
945+ // While there are safe nodes that we can visit.
946+ while (!can_be_solved.empty ())
947+ {
948+ auto solved = can_be_solved.front ();
949+ // Visit the node.
950+ can_be_solved.pop ();
951+ // Decrease number of nodes that need to be traversed.
952+ remain--;
953+
954+ // Visit all the children of the visited node.
955+ auto it = adjMatrix.find (solved);
956+ if (it != adjMatrix.end ())
957+ {
958+ for (auto child : it->second )
959+ {
960+ // Check if we can visited the node safely.
961+ if (--indegree[std::get<0 >(child)->getId ()] == 0 )
962+ {
963+ // if node can be visited safely, then add that node to
964+ // the visit queue.
965+ can_be_solved.emplace (std::get<0 >(child));
966+ }
967+ }
968+ }
969+ }
970+
971+ // If there are still nodes that we can't visit, then it means that
972+ // there is a cycle and return true, else return false.
973+ return !(remain == 0 );
974+ }
975+
976+ template <typename T>
896977 const bool Graph<T>::isDirectedGraph() const
897978 {
898979 auto edgeSet = this ->getEdgeSet ();
899- for ( auto edge : edgeSet){
900- if ( !(edge->isDirected ().has_value () && edge->isDirected ().value ())){
980+ for (auto edge : edgeSet)
981+ {
982+ if (!(edge->isDirected ().has_value () && edge->isDirected ().value ()))
983+ {
901984 // Found Undirected Edge
902985 return false ;
903986 }
0 commit comments