@@ -509,6 +509,22 @@ namespace CXXGRAPH
509
509
*/
510
510
const std::vector<Node<T>> depth_first_search (const Node<T> &start) const ;
511
511
512
+ /* *
513
+ * \brief
514
+ * This function uses DFS to check for cycle in the graph.
515
+ * Pay Attention, this function work only with directed Graph
516
+ *
517
+ * @return true if a cycle is detected, else false. ( false is returned also if the graph in indirected)
518
+ */
519
+ const bool isCyclicDFS () const ;
520
+ /* *
521
+ * \brief
522
+ * This function checks if a graph is directed
523
+ *
524
+ * @return true if the graph is directed, else false.
525
+ */
526
+ const bool isDirectedGraph () const ;
527
+
512
528
friend std::ostream &operator <<<>(std::ostream &os, const Graph<T> &graph);
513
529
friend std::ostream &operator <<<>(std::ostream &os, const AdjacencyMatrix<T> &adj);
514
530
};
@@ -767,9 +783,10 @@ namespace CXXGRAPH
767
783
{
768
784
return visited;
769
785
}
770
- const AdjacencyMatrix<T> adj = getAdjMatrix ();
786
+ const AdjacencyMatrix<T> adj = getAdjMatrix ();
771
787
std::function<void (const AdjacencyMatrix<T> &, const Node<T> &, std::vector<Node<T>> &)> explore;
772
- explore = [&explore](const AdjacencyMatrix<T> &adj, const Node<T> &node, std::vector<Node<T>> &visited) -> void {
788
+ explore = [&explore](const AdjacencyMatrix<T> &adj, const Node<T> &node, std::vector<Node<T>> &visited) -> void
789
+ {
773
790
visited.push_back (node);
774
791
if (adj.find (&node) != adj.end ())
775
792
{
@@ -787,20 +804,122 @@ namespace CXXGRAPH
787
804
return visited;
788
805
}
789
806
807
+ template <typename T>
808
+ const bool Graph<T>::isCyclicDFS() const
809
+ {
810
+ if (!isDirectedGraph ()){
811
+ return false ;
812
+ }
813
+ enum nodeStates : uint8_t
814
+ {
815
+ not_visited,
816
+ in_stack,
817
+ visited
818
+ };
819
+ auto nodeSet = this ->getNodeSet ();
820
+ auto adjMatrix = this ->getAdjMatrix ();
821
+
822
+ /* * State of the node.
823
+ *
824
+ * It is a vector of "nodeStates" which represents the state node is in.
825
+ * It can take only 3 values: "not_visited", "in_stack", and "visited".
826
+ *
827
+ * Initially, all nodes are in "not_visited" state.
828
+ */
829
+ std::map<unsigned long ,nodeStates> state;
830
+ for (auto node : nodeSet){
831
+ state[node->getId ()] = not_visited;
832
+ }
833
+ int stateCounter = 0 ;
834
+
835
+ // Start visiting each node.
836
+ for (auto node : nodeSet)
837
+ {
838
+ // If a node is not visited, only then check for presence of cycle.
839
+ // There is no need to check for presence of cycle for a visited
840
+ // node as it has already been checked for presence of cycle.
841
+ if (state[node->getId ()] == not_visited)
842
+ {
843
+ // 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)
846
+ {
847
+ // Add node "in_stack" state.
848
+ states[node->getId ()] = in_stack;
849
+
850
+ // If the node has children, then recursively visit all children of the
851
+ // node.
852
+ auto const it = adjMatrix.find (node);
853
+ if (it != adjMatrix.end ())
854
+ {
855
+ for (auto child : it->second )
856
+ {
857
+ // If state of child node is "not_visited", evaluate that child
858
+ // for presence of cycle.
859
+ auto state_of_child = states.at ((std::get<0 >(child))->getId ());
860
+ if (state_of_child == not_visited)
861
+ {
862
+ if (isCyclicDFSHelper (adjMatrix, states, std::get<0 >(child)))
863
+ {
864
+ return true ;
865
+ }
866
+ }
867
+ else if (state_of_child == in_stack)
868
+ {
869
+ // If child node was "in_stack", then that means that there
870
+ // is a cycle in the graph. Return true for presence of the
871
+ // cycle.
872
+ return true ;
873
+ }
874
+ }
875
+ }
876
+
877
+ // Current node has been evaluated for the presence of cycle and had no
878
+ // cycle. Mark current node as "visited".
879
+ states[node->getId ()] = visited;
880
+ // Return that current node didn't result in any cycles.
881
+ return false ;
882
+ };
883
+ if (isCyclicDFSHelper (adjMatrix, state, node))
884
+ {
885
+ return true ;
886
+ }
887
+ }
888
+ }
889
+
890
+ // All nodes have been safely traversed, that means there is no cycle in
891
+ // the graph. Return false.
892
+ return false ;
893
+ }
894
+
895
+ template <typename T>
896
+ const bool Graph<T>::isDirectedGraph() const
897
+ {
898
+ auto edgeSet = this ->getEdgeSet ();
899
+ for ( auto edge : edgeSet){
900
+ if ( !(edge->isDirected ().has_value () && edge->isDirected ().value ())){
901
+ // Found Undirected Edge
902
+ return false ;
903
+ }
904
+ }
905
+ // No Undirected Edge
906
+ return true ;
907
+ }
908
+
790
909
// ostream overload
791
910
template <typename T>
792
911
std::ostream &operator <<(std::ostream &os, const Node<T> &node)
793
912
{
794
913
os << " Node: {\n "
795
914
<< " Id:\t " << node.id << " \n Data:\t " << node.data << " \n }" ;
796
- return os;
915
+ return os;
797
916
}
798
917
799
918
template <typename T>
800
919
std::ostream &operator <<(std::ostream &os, const Edge<T> &edge)
801
920
{
802
921
os << " ((Node: " << edge.nodePair .first ->getId () << " )) ?----- |Edge: " << edge.id << " |-----? ((Node: " << edge.nodePair .second ->getId () << " ))" ;
803
- retrun os;
922
+ return os;
804
923
}
805
924
806
925
template <typename T>
0 commit comments