diff --git a/Headers/0003_Graph/0003_TopologicalSort.h b/Headers/0003_Graph/0003_TopologicalSort.h index f3cac62..f634c72 100644 --- a/Headers/0003_Graph/0003_TopologicalSort.h +++ b/Headers/0003_Graph/0003_TopologicalSort.h @@ -17,6 +17,7 @@ namespace TopologicalSort int color; int discoveryTime; int finishingTime; + int inDegree; Node* parent; Node(int value); }; @@ -35,6 +36,7 @@ namespace TopologicalSort void PushDirectedEdge(int valueU, int valueV); void PushSingleNode(int valueU); void TopologicalSort(); + void KahnTopologicalSort(); vector>> ShowTopologicalSortResult(); }; } \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0003_TopologicalSort.cc b/SourceCodes/0003_Graph/0003_TopologicalSort.cc index 526456c..e0912ff 100644 --- a/SourceCodes/0003_Graph/0003_TopologicalSort.cc +++ b/SourceCodes/0003_Graph/0003_TopologicalSort.cc @@ -1,5 +1,6 @@ #include "../Headers/0003_Graph/0003_TopologicalSort.h" #include +#include #include #include #include @@ -10,9 +11,10 @@ namespace TopologicalSort Node::Node(int value) { this->data = value; + this->color = WHITE; this->discoveryTime = INT_MAX; this->finishingTime = INT_MAX; - this->color = WHITE; + this->inDegree = 0; this->parent = nullptr; } @@ -61,6 +63,7 @@ namespace TopologicalSort Node* nodeV = this->MakeOrFindNode(valueV); this->_adjlist[nodeU].push_back(nodeV); + nodeV->inDegree++; } void Graph::PushSingleNode(int valueU) @@ -84,6 +87,53 @@ namespace TopologicalSort } } + void Graph::KahnTopologicalSort() + { + // Step-1 Compute in-degree of each vertices + // This is already done while creating the graph + this->time = 0; + queue nodeQueue; + + // Step-2 Enqueue vertices with in-degree 0 + for (auto& node : this->_nodeMap) + { + if (node.second->inDegree == 0) + { + this->time++; + node.second->discoveryTime = time; + nodeQueue.push(node.second); + } + } + + // Step-3 Process vertices in queue + while (!nodeQueue.empty()) + { + Node* node = nodeQueue.front(); + nodeQueue.pop(); + this->time++; + node->finishingTime = time; + this->_topologicalSortedNodeList.push_back(node); + + // Step-4 Process all the neighbours of current node based on in-degree + for (auto& neighbour : this->_adjlist[node]) + { + neighbour->inDegree--; + if (neighbour->inDegree == 0) + { + this->time++; + neighbour->discoveryTime = time; + nodeQueue.push(neighbour); + } + } + } + + // Step-5 Check if a cycle exists + if (this->_topologicalSortedNodeList.size() != this->_nodeMap.size()) + { + this->hasCycle = true; + } + } + vector>> Graph::ShowTopologicalSortResult() { if (this->hasCycle == true) diff --git a/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc b/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc index 3da8a1f..199cc34 100644 --- a/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc +++ b/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc @@ -141,8 +141,12 @@ namespace AllPairsShortestPathsJohnson // Creating the graph G' this->_augmentedAdjlist = this->_adjlist; this->_augmentedEdgeList = this->_edgeList; + + // Source Node s Node* source = new Node(0); this->_nodeMap[0] = source; + + // Creating all the augmented edges in G'.E = G.E U {(s, v) : v in G.V for (auto& node : this->_nodeMap) { if (node.second != source) diff --git a/Tests/0003_Graph/0003_TopologicalSortTest.cc b/Tests/0003_Graph/0003_TopologicalSortTest.cc index b069e2e..2447951 100644 --- a/Tests/0003_Graph/0003_TopologicalSortTest.cc +++ b/Tests/0003_Graph/0003_TopologicalSortTest.cc @@ -104,4 +104,41 @@ namespace TopologicalSort // Expected output if cycle detection is implemented EXPECT_THROW(graph.ShowTopologicalSortResult(), runtime_error); } + + TEST(TopoSortTesting, ShowTopoSortResultUsingKahnAlgorithm) + { + Graph graph; + + graph.PushDirectedEdge(1, 2); + graph.PushDirectedEdge(1, 4); + graph.PushDirectedEdge(2, 3); + graph.PushDirectedEdge(4, 3); + graph.PushSingleNode(5); + graph.PushDirectedEdge(6, 7); + graph.PushDirectedEdge(6, 8); + graph.PushDirectedEdge(7, 4); + graph.PushDirectedEdge(7, 8); + graph.PushDirectedEdge(9, 8); + + graph.KahnTopologicalSort(); + + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowTopologicalSortResult()); + string expectedResult = "1(1,5) 5(2,7) 6(3,8) 9(4,10) 2(6,11) 7(9,12) 4(13,15) 8(14,17) 3(16,18)"; + + EXPECT_EQ(actualResult, expectedResult); + } + + // Test with a cyclic graph to verify it can detect cycles + TEST(TopoSortTesting, CyclicGraphUsingKahnAlgorithm) + { + Graph graph; + graph.PushDirectedEdge(1, 2); + graph.PushDirectedEdge(2, 3); + graph.PushDirectedEdge(3, 1); // Cycle: 1 -> 2 -> 3 -> 1 + + graph.KahnTopologicalSort(); + + // Expected output if cycle detection is implemented + EXPECT_THROW(graph.ShowTopologicalSortResult(), runtime_error); + } } \ No newline at end of file