├── DirectedGraph.h ├── Graph.h ├── README.md └── UndirectedGraph.h /DirectedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef DIRECTEDGRAPH_H 2 | #define DIRECTEDGRAPH_H 3 | #include 4 | #include "Graph.h" 5 | using namespace std; 6 | 7 | class DirectedGraph : public Graph 8 | { 9 | public: 10 | DirectedGraph(int nodes) : Graph(nodes) 11 | { 12 | 13 | } 14 | 15 | virtual bool isCyclic(); 16 | 17 | virtual void addEdge(int u, int v, long long w = 1) 18 | { 19 | adjacencyList[u].push_back({v, w}); 20 | } 21 | vector> getStronglyConnectedComponents(); 22 | 23 | private: 24 | 25 | vector getFinishTimes(); 26 | void finishTimeHelper(int src, vector& finishTimes, vector& visited); 27 | DirectedGraph getReversal(); 28 | 29 | }; 30 | 31 | vector> DirectedGraph :: getStronglyConnectedComponents() 32 | { 33 | vector> stronglyConnectedComponents; 34 | vector finishTimes = this -> getFinishTimes(); 35 | DirectedGraph reversedGraph = this -> getReversal(); 36 | 37 | vector visited(this -> getNumberOfNodes() + 1, 0); 38 | 39 | for(int i = finishTimes.size() - 1; i >= 0; i--) 40 | { 41 | vector SCC; 42 | if(!visited[finishTimes[i]]) 43 | { 44 | reversedGraph.dfsHelper(finishTimes[i], SCC, visited); 45 | stronglyConnectedComponents.push_back(SCC); 46 | } 47 | } 48 | 49 | return stronglyConnectedComponents; 50 | } 51 | 52 | vector DirectedGraph :: getFinishTimes() 53 | { 54 | vector finishTimes; 55 | vector visited(this -> getNumberOfNodes() + 1, 0); 56 | 57 | for(int src = 1; src <= this -> getNumberOfNodes(); src++) 58 | { 59 | if(!visited[src]) 60 | { 61 | finishTimeHelper(src, finishTimes, visited); 62 | } 63 | } 64 | 65 | return finishTimes; 66 | } 67 | 68 | 69 | void DirectedGraph :: finishTimeHelper(int src, vector& finishTimes, vector& visited) 70 | { 71 | visited[src] = 1; 72 | 73 | for(auto neighbour : this -> adjacencyList[src]) 74 | { 75 | if(!visited[neighbour.first]) 76 | finishTimeHelper(neighbour.first, finishTimes, visited); 77 | } 78 | 79 | finishTimes.push_back(src); 80 | } 81 | 82 | DirectedGraph DirectedGraph :: getReversal() 83 | { 84 | DirectedGraph gT(this -> getNumberOfNodes()); 85 | 86 | for(int node = 1; node <= this -> getNumberOfNodes(); node++) 87 | { 88 | for(auto edge : adjacencyList[node]) 89 | { 90 | gT.addEdge(edge.first, node); 91 | } 92 | } 93 | 94 | return gT; 95 | } 96 | 97 | bool DirectedGraph::isCyclic() 98 | { 99 | int numOfNodes = getNumberOfNodes(); 100 | if(numOfNodes <= 1) 101 | return false; 102 | vector visited(numOfNodes + 1, 0); 103 | vector inPath(numOfNodes + 1, 0); 104 | stack> path; 105 | for(int i=1; i <= numOfNodes; i++) 106 | { 107 | if(visited[i]) 108 | continue; 109 | path.push({i,0}); 110 | visited[i] = 1; 111 | inPath[i] = 1; 112 | while(!path.empty()) 113 | { 114 | int source = path.top().first; 115 | int idx = path.top().second; 116 | path.pop(); 117 | if(idx == adjacencyList[source].size()) 118 | { 119 | inPath[idx] = 0; 120 | continue; 121 | } 122 | else 123 | { 124 | int explore = adjacencyList[source][idx].first; 125 | if(inPath[explore]) 126 | return true; 127 | if(visited[explore]) 128 | { 129 | path.push({source, idx + 1}); 130 | continue; 131 | } 132 | inPath[explore] = visited[explore] = true; 133 | path.push({source, idx + 1}); 134 | path.push({explore, 0}); 135 | } 136 | } 137 | } 138 | return false; 139 | } 140 | 141 | #endif // DIRECTEDGRAPH_H 142 | -------------------------------------------------------------------------------- /Graph.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPH_H 2 | #define GRAPH_H 3 | #include 4 | #include 5 | using namespace std; 6 | class Graph 7 | { 8 | public: 9 | Graph(int nodes) 10 | { 11 | numOfNodes = nodes; 12 | adjacencyList = vector>>(nodes+1); 13 | } 14 | virtual void addEdge(int u, int v, long long weight) = 0; 15 | virtual bool isCyclic() = 0; 16 | vector breadthFirstTraversal(int source); 17 | vector depthFirstTraversal(int source); 18 | int getNumberOfNodes() 19 | { 20 | return numOfNodes; 21 | } 22 | protected: 23 | //number of nodes in the graph 24 | int numOfNodes; 25 | //adjacency list for the graph 26 | //adjList[i] represents direct neighbours of node i 27 | //adjList[i].first represents an edge from node i to 28 | //node adjList[i].first. 29 | //adjList[i].second represents weight of the edge. 30 | vector>> adjacencyList; 31 | void dfsHelper(int source, vector &nodesDiscovered, vector &vis); 32 | 33 | }; 34 | 35 | vector Graph::breadthFirstTraversal(int source) 36 | { 37 | vector nodesDiscovered; 38 | queue nodesToExplore; 39 | vector visited(numOfNodes+1, 0); 40 | 41 | nodesToExplore.push(source); 42 | visited[source] = true; 43 | 44 | while(!nodesToExplore.empty()) 45 | { 46 | int explore = nodesToExplore.front(); 47 | nodesToExplore.pop(); 48 | nodesDiscovered.push_back(explore); 49 | 50 | for(pair neighbours : adjacencyList[explore]) 51 | { 52 | int neighbour = neighbours.first; 53 | if(!visited[neighbour]) 54 | { 55 | visited[neighbour] = 1; 56 | nodesToExplore.push(neighbour); 57 | } 58 | } 59 | } 60 | return nodesDiscovered; 61 | } 62 | 63 | void Graph::dfsHelper(int source,vector &nodesDiscovered, vector &vis) 64 | { 65 | vis[source] = 1; 66 | nodesDiscovered.push_back(source); 67 | 68 | for(pair neighbours : adjacencyList[source]) 69 | { 70 | int neighbour = neighbours.first; 71 | if(!vis[neighbour]) 72 | { 73 | dfsHelper(neighbour, nodesDiscovered, vis); 74 | } 75 | } 76 | } 77 | 78 | vector Graph::depthFirstTraversal(int source) 79 | { 80 | vector nodesDiscovered; 81 | vector vis(numOfNodes + 1, 0); 82 | dfsHelper(source, nodesDiscovered, vis); 83 | return nodesDiscovered; 84 | } 85 | 86 | #endif // GRAPH_H 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graph 2 | An implementation for the graph data structure along with implementation of common graph algorithms. 3 | An abstract base class Graph is used to model a graph. 4 | The derived classes DirectedGraph and UndirectedGraph inherit from class Graph. 5 | 6 | Currently added features: 7 | 1. Create a Graph with N vertices. 8 | 2. Add an unweighted edge between two vertices u,v. 9 | 3. Add a weighted edge between two vertices u,v. 10 | 4. Traverse the Graph using BFS or DFS. 11 | 5. Check if the Graph is cyclic. 12 | 6. Get the strongly connected components of a Directed Graph. 13 | -------------------------------------------------------------------------------- /UndirectedGraph.h: -------------------------------------------------------------------------------- 1 | ///author : kartik8800 2 | #ifndef UNDIRECTEDGRAPH_H 3 | #define UNDIRECTEDGRAPH_H 4 | 5 | #include "Graph.h" 6 | 7 | 8 | class UndirectedGraph : public Graph 9 | { 10 | private: 11 | void detectCycle(int src, vector &parent, vector &visited, bool &cycle); 12 | public: 13 | UndirectedGraph(int nodes) : Graph(nodes) 14 | { 15 | 16 | } 17 | 18 | virtual bool isCyclic(); 19 | 20 | virtual void addEdge(int u, int v, long long w = 1) 21 | { 22 | adjacencyList[u].push_back({v, w}); 23 | adjacencyList[v].push_back({u, w}); 24 | } 25 | 26 | }; 27 | 28 | bool UndirectedGraph::isCyclic() 29 | { 30 | if(numOfNodes <= 1) 31 | return false; 32 | vector parent(numOfNodes + 1); 33 | vector visited(numOfNodes + 1, 0); 34 | bool cycle = 0; 35 | parent[1] = 1; 36 | detectCycle(1, parent, visited, cycle); 37 | return cycle; 38 | } 39 | 40 | void UndirectedGraph:: 41 | detectCycle(int source, vector &parent, vector &visited, bool &cycle) 42 | { 43 | if(cycle) 44 | return; 45 | visited[source] = 1; 46 | for(auto neighbours : adjacencyList[source]) 47 | { 48 | int neighbour = neighbours.first; 49 | if(visited[neighbour] && parent[source] != neighbour) 50 | { 51 | cycle = 1; 52 | return; 53 | } 54 | else if(!visited[neighbour]) 55 | { 56 | parent[neighbour] = source; 57 | detectCycle(neighbour, parent, visited, cycle); 58 | } 59 | } 60 | } 61 | 62 | #endif // UNDIRECTEDGRAPH_H 63 | --------------------------------------------------------------------------------