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..5993123 --- /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); + void DepthFirstSearchOnGraphT(SCCNode* DFSNode, vector& connectedComponents); +public: + void PushDirectedEdge(int valueU, int valueV); + void PushSingleNode(int valueU); + void DFSOnGraphG(); + void DFSOnGraphT(); + vector> 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..1e2677b --- /dev/null +++ b/SourceCodes/0003_Graph/0004_StronglyConnectedComponents.cc @@ -0,0 +1,118 @@ +#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); +} + +void StronglyConnectedComponentsGraph::DepthFirstSearchOnGraphT(SCCNode* nodeU, vector& connectedComponents) +{ + nodeU->color = GRAY; + connectedComponents.push_back(nodeU->data); + for (auto nodeV : this->_adjlistT[nodeU]) + { + if (nodeV->color == WHITE) + { + nodeV->parent = nodeU; + this->DepthFirstSearchOnGraphT(nodeV, connectedComponents); + } + } + nodeU->color = BLACK; +} + +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->_adjlistT[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; + this->DepthFirstSearchOnGraphT(iterator, connectedComponents); + this->_allConnectedComponents.push_back(connectedComponents); + } + } +} + +vector> StronglyConnectedComponentsGraph::FindAllStronglyConnectedComponents() +{ + this->DFSOnGraphG(); + this->DFSOnGraphT(); + return this->_allConnectedComponents; +} \ 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/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index 5df489e..9ab647a 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -51,4 +51,24 @@ class UnitTestHelper } return result; } + + template + string VerifyVectorResult(vector> vector) + { + string result = ""; + for (auto& iterator : vector) + { + result += "["; + for (auto& it : iterator) + { + result += to_string(it) + " "; + } + if (!result.empty()) + { + result.pop_back(); + } + 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 new file mode 100644 index 0000000..cc245e6 --- /dev/null +++ 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(1, 5); + graph.PushDirectedEdge(2, 3); + graph.PushDirectedEdge(2, 4); + graph.PushDirectedEdge(3, 2); + graph.PushDirectedEdge(4, 4); + graph.PushDirectedEdge(5, 1); + graph.PushDirectedEdge(5, 4); + graph.PushDirectedEdge(6, 1); + graph.PushDirectedEdge(6, 3); + graph.PushDirectedEdge(6, 7); + graph.PushDirectedEdge(7, 3); + graph.PushDirectedEdge(7, 8); + graph.PushDirectedEdge(8, 6); + + string actualResult = unitTestHelper.VerifyVectorResult(graph.FindAllStronglyConnectedComponents()); + string expectedResult = "[6 8 7][1 5][2 3][4]"; + EXPECT_EQ(actualResult, expectedResult); + } +} \ No newline at end of file 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(