From 5c2571e6ca01886192fe532cc4d065b47552cf87 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Sun, 27 Oct 2024 22:38:20 +0530 Subject: [PATCH 1/3] scc initial code added --- Headers/0003_Graph/0003_TopologicalSort.h | 2 +- .../0004_StronglyConnectedComponents.h | 39 ++++++ .../0004_StronglyConnectedComponents.cc | 117 ++++++++++++++++++ SourceCodes/0003_Graph/CMakeLists.txt | 1 + .../0004_StronglyConnectedComponentsTest.cc | 0 Tests/0003_Graph/CMakeLists.txt | 1 + 6 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 Headers/0003_Graph/0004_StronglyConnectedComponents.h create mode 100644 SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc create mode 100644 Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc diff --git a/Headers/0003_Graph/0003_TopologicalSort.h b/Headers/0003_Graph/0003_TopologicalSort.h index b4dd489..b8d6d36 100644 --- a/Headers/0003_Graph/0003_TopologicalSort.h +++ b/Headers/0003_Graph/0003_TopologicalSort.h @@ -25,8 +25,8 @@ class TopologicalSortGraph bool hasCycle; map> _adjlist; map _nodeMap; - TopologicalSortNode* MakeOrFindNode(int value); list _topologicalSortedNodeList; + TopologicalSortNode* MakeOrFindNode(int value); void DepthFirstSearch(TopologicalSortNode* DFSNode); public: void PushDirectedEdge(int valueU, int valueV); diff --git a/Headers/0003_Graph/0004_StronglyConnectedComponents.h b/Headers/0003_Graph/0004_StronglyConnectedComponents.h new file mode 100644 index 0000000..66d4c9c --- /dev/null +++ b/Headers/0003_Graph/0004_StronglyConnectedComponents.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include +using namespace std; +enum color { WHITE, GRAY, BLACK }; + +class SCCNode +{ +public: + int data; + int color; + int discoveryTime; + int finishingTime; + SCCNode* parent; + SCCNode(int value); +}; + +class StronglyConnectedComponentsGraph +{ +private: + int time; + map> _adjlistG; + map> _adjlistT; + map _nodeMap; + list _nodesFinishingTimeOrder; + vector> _allConnectedComponents; + SCCNode* MakeOrFindNode(int value); + void DepthFirstSearchOnGraphG(SCCNode* DFSNode); + vector DepthFirstSearchOnGraphT(SCCNode* DFSNode, vector connectedComponents); +public: + void PushDirectedEdge(int valueU, int valueV); + void PushSingleNode(int valueU); + void DFSOnGraphG(); + void DFSOnGraphT(); + void FindAllStronglyConnectedComponents(); +}; \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc new file mode 100644 index 0000000..6fe992f --- /dev/null +++ b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc @@ -0,0 +1,117 @@ +#include "../Headers/0003_Graph/0004_StronglyConnectedComponents.h" +#include +#include +#include +using namespace std; + +SCCNode::SCCNode(int value) +{ + this->data = value; + this->discoveryTime = INT_MAX; + this->finishingTime = INT_MAX; + this->color = WHITE; + this->parent = nullptr; +} + +SCCNode* StronglyConnectedComponentsGraph::MakeOrFindNode(int value) +{ + SCCNode* node = nullptr; + if (this->_nodeMap.find(value) == this->_nodeMap.end()) + { + node = new SCCNode(value); + this->_nodeMap[value] = node; + } + else + { + node = this->_nodeMap[value]; + } + return node; +} + +void StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphG(SCCNode* nodeU) +{ + this->time++; + nodeU->discoveryTime = this->time; + nodeU->color = GRAY; + for (auto nodeV : this->_adjlistG[nodeU]) + { + if (nodeV->color == WHITE) + { + nodeV->parent = nodeU; + this->DepthFirstSearchOnGraphG(nodeV); + } + } + nodeU->color = BLACK; + this->time++; + nodeU->finishingTime = time; + this->_nodesFinishingTimeOrder.push_front(nodeU); +} + +vector StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* nodeU, vector connectedComponents) +{ + nodeU->color = GRAY; + for (auto nodeV : this->_adjlistG[nodeU]) + { + if (nodeV->color == WHITE) + { + nodeV->parent = nodeU; + this->DepthFirstSearchOnGraphT(nodeV, connectedComponents); + } + } + nodeU->color = BLACK; + return connectedComponents; +} + +void StronglyConnectedComponentsGraph::PushDirectedEdge(int valueU, int valueV) +{ + SCCNode* nodeU = this->MakeOrFindNode(valueU); + SCCNode* nodeV = this->MakeOrFindNode(valueV); + + // Creating the actual graph. + this->_adjlistG[nodeU].push_back(nodeV); + + // Creating the transpose of the actual graph. + this->_adjlistG[nodeV].push_back(nodeU); +} + +void StronglyConnectedComponentsGraph::PushSingleNode(int valueU) +{ + SCCNode* nodeU = this->MakeOrFindNode(valueU); +} + +void StronglyConnectedComponentsGraph::DFSOnGraphG() +{ + this->time = 0; + for (auto& iterator : this->_nodeMap) + { + if (iterator.second->color == WHITE) + { + this->DepthFirstSearchOnGraphG(iterator.second); + } + } +} + +void StronglyConnectedComponentsGraph::DFSOnGraphT() +{ + for (auto& iterator : this->_nodeMap) + { + iterator.second->color = WHITE; + iterator.second->parent = nullptr; + } + + for (auto& iterator : this->_nodesFinishingTimeOrder) + { + if (iterator->color == WHITE) + { + vector connectedComponents; + auto result = this->DepthFirstSearchOnGraphT(iterator, connectedComponents); + this->_allConnectedComponents.push_back(result); + } + } +} + + +void StronglyConnectedComponentsGraph::FindAllStronglyConnectedComponents() +{ + this->DFSOnGraphG(); +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index adc8f1e..9df817b 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -3,6 +3,7 @@ set(0003GRAPH_SOURCES 0001_BreadthFirstSearch.cc 0002_DepthFirstSearch.cc 0003_TopologicalSort.cc + 0004_StronglyConnectedComponents.cc ) # Create a library target diff --git a/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc b/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc new file mode 100644 index 0000000..e69de29 diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index d8defca..b43d3d3 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable( 0001_BreadthFirstSearchTest.cc 0002_DepthFirstSearchTest.cc 0003_TopologicalSortTest.cc + 0004_StronglyConnectedComponentsTest.cc ) target_link_libraries( From f490d33a535a5ec57e2c48703bc07da3237fd1c3 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Mon, 28 Oct 2024 01:46:26 +0530 Subject: [PATCH 2/3] fixed some errors in the scc logic --- .../0004_StronglyConnectedComponents.h | 6 ++-- .../0004_StronglyConnectedComponents.cc | 14 ++++---- Tests/0000_CommonUtilities/UnitTestHelper.h | 16 ++++++++++ .../0004_StronglyConnectedComponentsTest.cc | 32 +++++++++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/Headers/0003_Graph/0004_StronglyConnectedComponents.h b/Headers/0003_Graph/0004_StronglyConnectedComponents.h index 66d4c9c..5db81d3 100644 --- a/Headers/0003_Graph/0004_StronglyConnectedComponents.h +++ b/Headers/0003_Graph/0004_StronglyConnectedComponents.h @@ -26,14 +26,14 @@ class StronglyConnectedComponentsGraph map> _adjlistT; map _nodeMap; list _nodesFinishingTimeOrder; - vector> _allConnectedComponents; + vector> _allConnectedComponents; SCCNode* MakeOrFindNode(int value); void DepthFirstSearchOnGraphG(SCCNode* DFSNode); - vector DepthFirstSearchOnGraphT(SCCNode* DFSNode, vector connectedComponents); + vector DepthFirstSearchOnGraphT(SCCNode* DFSNode, vector connectedComponents); public: void PushDirectedEdge(int valueU, int valueV); void PushSingleNode(int valueU); void DFSOnGraphG(); void DFSOnGraphT(); - void FindAllStronglyConnectedComponents(); + vector> FindAllStronglyConnectedComponents(); }; \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc index 6fe992f..7df85e7 100644 --- a/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc +++ b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc @@ -47,10 +47,11 @@ void StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphG(SCCNode* nodeU) this->_nodesFinishingTimeOrder.push_front(nodeU); } -vector StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* nodeU, vector connectedComponents) +vector StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* nodeU, vector connectedComponents) { nodeU->color = GRAY; - for (auto nodeV : this->_adjlistG[nodeU]) + connectedComponents.push_back(nodeU->data); + for (auto nodeV : this->_adjlistT[nodeU]) { if (nodeV->color == WHITE) { @@ -71,7 +72,7 @@ void StronglyConnectedComponentsGraph::PushDirectedEdge(int valueU, int valueV) this->_adjlistG[nodeU].push_back(nodeV); // Creating the transpose of the actual graph. - this->_adjlistG[nodeV].push_back(nodeU); + this->_adjlistT[nodeV].push_back(nodeU); } void StronglyConnectedComponentsGraph::PushSingleNode(int valueU) @@ -103,15 +104,16 @@ void StronglyConnectedComponentsGraph::DFSOnGraphT() { if (iterator->color == WHITE) { - vector connectedComponents; + vector connectedComponents; auto result = this->DepthFirstSearchOnGraphT(iterator, connectedComponents); this->_allConnectedComponents.push_back(result); } } } - -void StronglyConnectedComponentsGraph::FindAllStronglyConnectedComponents() +vector> StronglyConnectedComponentsGraph::FindAllStronglyConnectedComponents() { this->DFSOnGraphG(); + this->DFSOnGraphT(); + return this->_allConnectedComponents; } \ No newline at end of file diff --git a/Tests/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index 5df489e..9fe52a6 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -51,4 +51,20 @@ class UnitTestHelper } return result; } + + template + string VerifyVectorResult(vector> vector) + { + string result = ""; + for (auto& iterator : vector) + { + result += "["; + for (auto& it : iterator) + { + result += to_string(it) + " "; + } + result += "]"; + } + return result; + } }; \ No newline at end of file diff --git a/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc b/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc index e69de29..96512e1 100644 --- a/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc +++ b/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc @@ -0,0 +1,32 @@ +#include +#include "../Headers/0003_Graph/0004_StronglyConnectedComponents.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace StronglyConnectedComponentsTest +{ + UnitTestHelper unitTestHelper; + + TEST(StronglyConnectedComponentsTesting, SimpleGraphTest) + { + StronglyConnectedComponentsGraph graph; + + graph.PushDirectedEdge(1, 2); + graph.PushDirectedEdge(2, 3); + graph.PushDirectedEdge(2, 5); + graph.PushDirectedEdge(2, 6); + graph.PushDirectedEdge(3, 4); + graph.PushDirectedEdge(3, 7); + graph.PushDirectedEdge(4, 3); + graph.PushDirectedEdge(4, 8); + graph.PushDirectedEdge(5, 1); + graph.PushDirectedEdge(5, 6); + graph.PushDirectedEdge(6, 7); + graph.PushDirectedEdge(7, 6); + graph.PushDirectedEdge(7, 8); + graph.PushDirectedEdge(8, 8); + + string actualResult = unitTestHelper.VerifyVectorResult(graph.FindAllStronglyConnectedComponents()); + string expectedResult = ""; + EXPECT_EQ(actualResult, expectedResult); + } +} \ No newline at end of file From f16d8821c0f7eeb917eea7fe64f32c0b2d83607c Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 30 Oct 2024 01:15:57 +0530 Subject: [PATCH 3/3] scc logic modified and test added --- .../0004_StronglyConnectedComponents.h | 2 +- .../0004_StronglyConnectedComponents.cc | 7 +++---- Tests/0000_CommonUtilities/UnitTestHelper.h | 4 ++++ .../0004_StronglyConnectedComponentsTest.cc | 20 +++++++++---------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Headers/0003_Graph/0004_StronglyConnectedComponents.h b/Headers/0003_Graph/0004_StronglyConnectedComponents.h index 5db81d3..5993123 100644 --- a/Headers/0003_Graph/0004_StronglyConnectedComponents.h +++ b/Headers/0003_Graph/0004_StronglyConnectedComponents.h @@ -29,7 +29,7 @@ class StronglyConnectedComponentsGraph vector> _allConnectedComponents; SCCNode* MakeOrFindNode(int value); void DepthFirstSearchOnGraphG(SCCNode* DFSNode); - vector DepthFirstSearchOnGraphT(SCCNode* DFSNode, vector connectedComponents); + void DepthFirstSearchOnGraphT(SCCNode* DFSNode, vector& connectedComponents); public: void PushDirectedEdge(int valueU, int valueV); void PushSingleNode(int valueU); diff --git a/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc index 7df85e7..1e2677b 100644 --- a/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc +++ b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc @@ -47,7 +47,7 @@ void StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphG(SCCNode* nodeU) this->_nodesFinishingTimeOrder.push_front(nodeU); } -vector StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* nodeU, vector connectedComponents) +void StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* nodeU, vector& connectedComponents) { nodeU->color = GRAY; connectedComponents.push_back(nodeU->data); @@ -60,7 +60,6 @@ vector StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* } } nodeU->color = BLACK; - return connectedComponents; } void StronglyConnectedComponentsGraph::PushDirectedEdge(int valueU, int valueV) @@ -105,8 +104,8 @@ void StronglyConnectedComponentsGraph::DFSOnGraphT() if (iterator->color == WHITE) { vector connectedComponents; - auto result = this->DepthFirstSearchOnGraphT(iterator, connectedComponents); - this->_allConnectedComponents.push_back(result); + this->DepthFirstSearchOnGraphT(iterator, connectedComponents); + this->_allConnectedComponents.push_back(connectedComponents); } } } diff --git a/Tests/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index 9fe52a6..9ab647a 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -63,6 +63,10 @@ class UnitTestHelper { result += to_string(it) + " "; } + if (!result.empty()) + { + result.pop_back(); + } result += "]"; } return result; diff --git a/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc b/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc index 96512e1..cc245e6 100644 --- a/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc +++ b/Tests/0003_Graph/0004_StronglyConnectedComponentsTest.cc @@ -11,22 +11,22 @@ namespace StronglyConnectedComponentsTest StronglyConnectedComponentsGraph graph; graph.PushDirectedEdge(1, 2); + graph.PushDirectedEdge(1, 5); graph.PushDirectedEdge(2, 3); - graph.PushDirectedEdge(2, 5); - graph.PushDirectedEdge(2, 6); - graph.PushDirectedEdge(3, 4); - graph.PushDirectedEdge(3, 7); - graph.PushDirectedEdge(4, 3); - graph.PushDirectedEdge(4, 8); + graph.PushDirectedEdge(2, 4); + graph.PushDirectedEdge(3, 2); + graph.PushDirectedEdge(4, 4); graph.PushDirectedEdge(5, 1); - graph.PushDirectedEdge(5, 6); + graph.PushDirectedEdge(5, 4); + graph.PushDirectedEdge(6, 1); + graph.PushDirectedEdge(6, 3); graph.PushDirectedEdge(6, 7); - graph.PushDirectedEdge(7, 6); + graph.PushDirectedEdge(7, 3); graph.PushDirectedEdge(7, 8); - graph.PushDirectedEdge(8, 8); + graph.PushDirectedEdge(8, 6); string actualResult = unitTestHelper.VerifyVectorResult(graph.FindAllStronglyConnectedComponents()); - string expectedResult = ""; + string expectedResult = "[6 8 7][1 5][2 3][4]"; EXPECT_EQ(actualResult, expectedResult); } } \ No newline at end of file