From 262410a52a90f826d385f79ca4ee1f9ec23ad9e6 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 22 Jan 2025 01:35:38 +0530 Subject: [PATCH 1/5] feature: floyd warshall added --- .../0013_AllPairsShortestPathsFloydWarshall.h | 24 ++++ ...0013_AllPairsShortestPathsFloydWarshall.cc | 104 ++++++++++++++++++ SourceCodes/0003_Graph/CMakeLists.txt | 1 + ..._AllPairsShortestPathsFloydWarshallTest.cc | 36 ++++++ Tests/0003_Graph/CMakeLists.txt | 1 + 5 files changed, 166 insertions(+) create mode 100644 Headers/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.h create mode 100644 SourceCodes/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.cc create mode 100644 Tests/0003_Graph/0013_AllPairsShortestPathsFloydWarshallTest.cc diff --git a/Headers/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.h b/Headers/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.h new file mode 100644 index 0000000..4dea0a1 --- /dev/null +++ b/Headers/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.h @@ -0,0 +1,24 @@ +#pragma once + +#include +using namespace std; + +namespace AllPairsShortestPathsFloydWarshall +{ + class Graph + { + private: + int _noOfVertices; + vector> _adjMatrix; + vector> _shortestPathMatrixFloydWarshall; + vector> _predecessorMatrix; + void InitializeDistanceAndPredecessors(); + void GetShortestPath(int source, int destination, vector& path); + + public: + void CreateGraph(int noOfVertices); + void PushDirectedEdge(int valueU, int valueV, int weight); + void FindAllPairsShortestPathsFloydWarshallSolution(); + vector> GetFloydWarshallShortestPath(); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.cc b/SourceCodes/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.cc new file mode 100644 index 0000000..53a6095 --- /dev/null +++ b/SourceCodes/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.cc @@ -0,0 +1,104 @@ +#include "../Headers/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.h" +#include +using namespace std; + +namespace AllPairsShortestPathsFloydWarshall +{ + // Graph Private Member Methods + void Graph::InitializeDistanceAndPredecessors() + { + this->_shortestPathMatrixFloydWarshall = this->_adjMatrix; + + for (int i = 0; i < this->_noOfVertices; i++) + { + for (int j = 0; j < this->_noOfVertices; j++) + { + if ((i == j) || this->_adjMatrix[i][j] == INT_MAX) + { + this->_predecessorMatrix[i][j] = -1; + } + else + { + this->_predecessorMatrix[i][j] = i + 1; + } + } + } + } + + void Graph::GetShortestPath(int source, int destination, vector& path) + { + if (this->_predecessorMatrix[source - 1][destination - 1] != source) + { + int predecessor = this->_predecessorMatrix[source - 1][destination - 1]; + this->GetShortestPath(source, predecessor, path); + path.push_back(predecessor); + } + } + + // Graph Public Member Methods + void Graph::CreateGraph(int noOfVertices) + { + this->_noOfVertices = noOfVertices; + this->_adjMatrix = vector>(this->_noOfVertices, vector(this->_noOfVertices, INT_MAX)); + this->_shortestPathMatrixFloydWarshall = vector>(this->_noOfVertices, vector(this->_noOfVertices, INT_MAX)); + this->_predecessorMatrix = vector>(this->_noOfVertices, vector(this->_noOfVertices, INT_MAX)); + + for (int i = 0; i < this->_noOfVertices; i++) + { + for (int j = 0; j < this->_noOfVertices; j++) + { + if (i == j) + { + this->_adjMatrix[i][j] = 0; + } + } + } + } + + void Graph::PushDirectedEdge(int valueU, int valueV, int weight) + { + this->_adjMatrix[valueU - 1][valueV - 1] = weight; + } + + void Graph::FindAllPairsShortestPathsFloydWarshallSolution() + { + this->InitializeDistanceAndPredecessors(); + + for (int k = 0; k < this->_noOfVertices; k++) + { + for (int i = 0; i < this->_noOfVertices; i++) + { + for (int j = 0; j < this->_noOfVertices; j++) + { + if ((this->_shortestPathMatrixFloydWarshall[i][j] > (this->_shortestPathMatrixFloydWarshall[i][k] + this->_shortestPathMatrixFloydWarshall[k][j])) + && + (this->_shortestPathMatrixFloydWarshall[i][k] != INT_MAX && this->_shortestPathMatrixFloydWarshall[k][j] != INT_MAX)) + { + this->_shortestPathMatrixFloydWarshall[i][j] = this->_shortestPathMatrixFloydWarshall[i][k] + this->_shortestPathMatrixFloydWarshall[k][j]; + this->_predecessorMatrix[i][j] = this->_predecessorMatrix[k][j]; + } + } + } + } + } + + vector> Graph::GetFloydWarshallShortestPath() + { + vector> result; + for (int i = 0; i < this->_noOfVertices; i++) + { + for (int j = 0; j < this->_noOfVertices; j++) + { + if (i != j) + { + vector path = {}; + path.push_back(i + 1); + this->GetShortestPath(i + 1, j + 1, path); + path.push_back(j + 1); + result.push_back(path); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index d2171df..4bfca4c 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -12,6 +12,7 @@ set(0003GRAPH_SOURCES 0010_DirectedAcyclicGraphShortestPath.cc 0011_SingleSourceShortestPathDijkstra.cc 0012_DifferenceConstraintsShortestPaths.cc + 0013_AllPairsShortestPathsFloydWarshall.cc ) diff --git a/Tests/0003_Graph/0013_AllPairsShortestPathsFloydWarshallTest.cc b/Tests/0003_Graph/0013_AllPairsShortestPathsFloydWarshallTest.cc new file mode 100644 index 0000000..d14130f --- /dev/null +++ b/Tests/0003_Graph/0013_AllPairsShortestPathsFloydWarshallTest.cc @@ -0,0 +1,36 @@ +#include +#include "../Headers/0003_Graph/0013_AllPairsShortestPathsFloydWarshall.h" +#include"../0000_CommonUtilities/UnitTestHelper.h" +using namespace std; + +namespace AllPairsShortestPathsFloydWarshall +{ + UnitTestHelper unitTestHelper; + + TEST(FloydWarshall, SimpleGraph) + { + // Arrange + Graph graph; + int noOfVertices = 5; + string expectedResult = "[1 5 4 3 2][1 5 4 3][1 5 4][1 5][2 4 1][2 4 3][2 4][2 4 1 5][3 2 4 1][3 2][3 2 4][3 2 4 1 5][4 1][4 3 2][4 3][4 1 5][5 4 1][5 4 3 2][5 4 3][5 4]"; + + // Act + graph.CreateGraph(noOfVertices); + + graph.PushDirectedEdge(1, 2, 3); + graph.PushDirectedEdge(1, 3, 8); + graph.PushDirectedEdge(1, 5, -4); + graph.PushDirectedEdge(2, 4, 1); + graph.PushDirectedEdge(2, 5, 7); + graph.PushDirectedEdge(3, 2, 4); + graph.PushDirectedEdge(4, 3, -5); + graph.PushDirectedEdge(4, 1, 2); + graph.PushDirectedEdge(5, 4, 6); + + graph.FindAllPairsShortestPathsFloydWarshallSolution(); + string actualResult = unitTestHelper.SerializeVectorToString(graph.GetFloydWarshallShortestPath()); + + // Assert + ASSERT_EQ(actualResult, expectedResult); + } +} \ No newline at end of file diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 1d024f1..3ec92b1 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable( 0010_DirectedAcyclicGraphShortestPathTest.cc 0011_SingleSourceShortestPathDijkstraTest.cc 0012_DifferenceConstraintsShortestPathsTest.cc + 0013_AllPairsShortestPathsFloydWarshallTest.cc ) target_link_libraries( From 5c53d9af75bd93d3e9a42ed56f8e0947ebb253be Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Sat, 25 Jan 2025 01:37:14 +0530 Subject: [PATCH 2/5] feature: johnson algo initial draft --- Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h | 10 ++++++++++ .../0003_Graph/0014_AllPairsShortestPathsJohnson.cc | 0 SourceCodes/0003_Graph/CMakeLists.txt | 1 + .../0014_AllPairsShortestPathsJohnsonTest.cc | 0 Tests/0003_Graph/CMakeLists.txt | 1 + 5 files changed, 12 insertions(+) create mode 100644 Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h create mode 100644 SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc create mode 100644 Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc diff --git a/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h b/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h new file mode 100644 index 0000000..c2eaaa1 --- /dev/null +++ b/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include +using namespace std; + +namespace AllPairsShortestPathsJohnson +{ + +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc b/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc new file mode 100644 index 0000000..e69de29 diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index 4bfca4c..23daf43 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -13,6 +13,7 @@ set(0003GRAPH_SOURCES 0011_SingleSourceShortestPathDijkstra.cc 0012_DifferenceConstraintsShortestPaths.cc 0013_AllPairsShortestPathsFloydWarshall.cc + 0014_AllPairsShortestPathsJohnson.cc ) diff --git a/Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc b/Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc new file mode 100644 index 0000000..e69de29 diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 3ec92b1..79b0409 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable( 0011_SingleSourceShortestPathDijkstraTest.cc 0012_DifferenceConstraintsShortestPathsTest.cc 0013_AllPairsShortestPathsFloydWarshallTest.cc + 0014_AllPairsShortestPathsJohnsonTest.cc ) target_link_libraries( From ee712db7886e99e51bdb559764b3b5e94908ce95 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Sun, 26 Jan 2025 22:28:42 +0530 Subject: [PATCH 3/5] feature-test: johnson algo logic, test added --- .../0014_AllPairsShortestPathsJohnson.h | 56 +++++ .../0014_AllPairsShortestPathsJohnson.cc | 213 ++++++++++++++++++ .../0014_AllPairsShortestPathsJohnsonTest.cc | 44 ++++ 3 files changed, 313 insertions(+) diff --git a/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h b/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h index c2eaaa1..388f727 100644 --- a/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h +++ b/Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h @@ -2,9 +2,65 @@ #include #include +#include using namespace std; namespace AllPairsShortestPathsJohnson { + class Node + { + public: + int data; + int distance; + Node* parent; + int potentialWeight; + Node(int data); + }; + class Edge + { + public: + Node* nodeU; + Node* nodeV; + int weight; + Edge(Node* nodeU, Node* nodeV, int weight); + }; + + class CompareNodeDistance + { + public: + bool operator()(const Node* nodeU, const Node* nodeV) const + { + return nodeU->distance < nodeV->distance; + } + }; + + class Graph + { + private: + int _noOfVertices=0; + map> _adjlist; + map _nodeMap; + vector _edgeList; + map> _edgeMap; + map> _augmentedAdjlist; + vector _augmentedEdgeList; + multiset _operationalSet; + vector> _shortestPathMatrix; + vector> _predecessorMatrix; + Node* MakeOrFindNode(int data); + void PushAugmentedDirectedEdges(Node* sourceNode, Node* nodeV, int weight); + void InitializeSingleSource(Node* sourceNode); + void RelaxBellmanFord(Edge* edge); + bool BellmanFord(Node* source); + void RelaxDijkstra(Edge* edge); + void Dijkstra(Node* source); + void GetShortestPath(int source, int destination, vector& path); + + public: + void PushDirectedEdge(int dataU, int dataV, int weight); + bool FindAllPairsShortestPathsJohnsonAlgorithm(); + vector> GetAllPairsShortestPathsDistanceMatrix(); + vector> GetAllPairsShortestPathsPathMatrix(); + }; } \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc b/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc index e69de29..3da8a1f 100644 --- a/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc +++ b/SourceCodes/0003_Graph/0014_AllPairsShortestPathsJohnson.cc @@ -0,0 +1,213 @@ +#include "../Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h" +#include +using namespace std; + +namespace AllPairsShortestPathsJohnson +{ + Node::Node(int data) + { + this->data = data; + this->distance = INT_MAX; + this->parent = nullptr; + this->potentialWeight = 0; + } + + Edge::Edge(Node* nodeU, Node* nodeV, int weight) + { + this->nodeU = nodeU; + this->nodeV = nodeV; + this->weight = weight; + } + + // Graph Private Member Methods + Node* Graph::MakeOrFindNode(int data) + { + Node* node = nullptr; + if (this->_nodeMap.find(data) == this->_nodeMap.end()) + { + node = new Node(data); + this->_nodeMap[data] = node; + } + else + { + node = this->_nodeMap[data]; + } + return node; + } + + void Graph::PushAugmentedDirectedEdges(Node* sourceNode, Node* nodeV, int weight) + { + this->_augmentedAdjlist[sourceNode].push_back(nodeV); + this->_augmentedEdgeList.push_back(new Edge(sourceNode, nodeV, weight)); + } + + void Graph::InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + iterator.second->parent = nullptr; + } + sourceNode->distance = 0; + } + + void Graph::RelaxBellmanFord(Edge* edge) + { + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) + { + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + edge->nodeV->parent = edge->nodeU; + } + } + + bool Graph::BellmanFord(Node* source) + { + this->InitializeSingleSource(source); + + for (int i = 0; i < this->_nodeMap.size() - 1; i++) + { + for (auto& edge : this->_augmentedEdgeList) + { + this->RelaxBellmanFord(edge); + } + } + + for (auto& edge : this->_augmentedEdgeList) + { + if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + { + return false; + } + } + return true; + } + + void Graph::RelaxDijkstra(Edge* edge) + { + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) + { + this->_operationalSet.erase(edge->nodeV); + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + edge->nodeV->parent = edge->nodeU; + this->_operationalSet.insert(edge->nodeV); + } + } + + void Graph::Dijkstra(Node* source) + { + this->InitializeSingleSource(source); + + for (auto& node : this->_nodeMap) + { + this->_operationalSet.insert(node.second); + } + + while (!this->_operationalSet.empty()) + { + Node* nodeU = *(this->_operationalSet.begin()); + this->_operationalSet.erase(nodeU); + + for (auto& edge : this->_edgeMap[nodeU]) + { + this->RelaxDijkstra(edge); + } + } + } + + void Graph::GetShortestPath(int source, int destination, vector& path) + { + if (this->_predecessorMatrix[source - 1][destination - 1] != source) + { + int predecessor = this->_predecessorMatrix[source - 1][destination - 1]; + this->GetShortestPath(source, predecessor, path); + path.push_back(predecessor); + } + } + + // Graph Public Member Methods + void Graph::PushDirectedEdge(int dataU, int dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + Edge* edge = new Edge(nodeU, nodeV, weight); + this->_edgeMap[nodeU].push_back(edge); + this->_edgeList.push_back(edge); + } + + bool Graph::FindAllPairsShortestPathsJohnsonAlgorithm() + { + // Creating the graph G' + this->_augmentedAdjlist = this->_adjlist; + this->_augmentedEdgeList = this->_edgeList; + Node* source = new Node(0); + this->_nodeMap[0] = source; + for (auto& node : this->_nodeMap) + { + if (node.second != source) + { + this->PushAugmentedDirectedEdges(source, node.second, 0); + } + } + + if (this->BellmanFord(source) == false) + { + return false; + } + else + { + this->_nodeMap.erase(0); + for (auto& node : this->_nodeMap) + { + node.second->potentialWeight = node.second->distance; + } + + for (auto& edge : this->_edgeList) + { + edge->weight = edge->weight + edge->nodeU->potentialWeight - edge->nodeV->potentialWeight; + } + + this->_noOfVertices = (int)this->_nodeMap.size(); + this->_shortestPathMatrix = vector>(this->_noOfVertices, vector(this->_noOfVertices, -1)); + this->_predecessorMatrix = vector>(this->_noOfVertices, vector(this->_noOfVertices, -1)); + for (auto& iteratorU : this->_nodeMap) + { + Node* nodeU = iteratorU.second; + this->Dijkstra(nodeU); + for (auto& iteratorV : this->_nodeMap) + { + Node* nodeV = iteratorV.second; + this->_shortestPathMatrix[nodeU->data - 1][nodeV->data - 1] = nodeV->distance + nodeV->potentialWeight - nodeU->potentialWeight; + this->_predecessorMatrix[nodeU->data - 1][nodeV->data - 1] = nodeV->parent != nullptr ? nodeV->parent->data : -1; + } + } + return true; + } + } + + vector> Graph::GetAllPairsShortestPathsDistanceMatrix() + { + return this->_shortestPathMatrix; + } + + vector> Graph::GetAllPairsShortestPathsPathMatrix() + { + vector> result; + for (int i = 0; i < this->_noOfVertices; i++) + { + for (int j = 0; j < this->_noOfVertices; j++) + { + if (i != j) + { + vector path = {}; + path.push_back(i + 1); + this->GetShortestPath(i + 1, j + 1, path); + path.push_back(j + 1); + result.push_back(path); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc b/Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc index e69de29..55610f2 100644 --- a/Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc +++ b/Tests/0003_Graph/0014_AllPairsShortestPathsJohnsonTest.cc @@ -0,0 +1,44 @@ +#include +#include"../Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h" +#include"../0000_CommonUtilities/UnitTestHelper.h" +using namespace std; + +namespace AllPairsShortestPathsJohnson +{ + UnitTestHelper unitTestHelper; + + TEST(JohnsonAlgorithm, SimpleGraph) + { + // Arrange + Graph graph; + vector> expectedDistanceMatrix = + { + {0, 1, -3, 2, -4}, + {3, 0, -4, 1, -1}, + {7, 4, 0, 5, 3}, + {2, -1, -5, 0, -2}, + {8, 5, 1, 6, 0}, + }; + string expectedPredecessorMatrixesult = "[1 5 4 3 2][1 5 4 3][1 5 4][1 5][2 4 1][2 4 3][2 4][2 4 1 5][3 2 4 1][3 2][3 2 4][3 2 4 1 5][4 1][4 3 2][4 3][4 1 5][5 4 1][5 4 3 2][5 4 3][5 4]"; + + // Act + graph.PushDirectedEdge(1, 2, 3); + graph.PushDirectedEdge(1, 3, 8); + graph.PushDirectedEdge(1, 5, -4); + graph.PushDirectedEdge(2, 4, 1); + graph.PushDirectedEdge(2, 5, 7); + graph.PushDirectedEdge(3, 2, 4); + graph.PushDirectedEdge(4, 3, -5); + graph.PushDirectedEdge(4, 1, 2); + graph.PushDirectedEdge(5, 4, 6); + + bool result = graph.FindAllPairsShortestPathsJohnsonAlgorithm(); + vector> actualDistanceMatrix = graph.GetAllPairsShortestPathsDistanceMatrix(); + string actualPredecessorMatrix = unitTestHelper.SerializeVectorToString(graph.GetAllPairsShortestPathsPathMatrix()); + + // Assert + ASSERT_TRUE(result); + ASSERT_EQ(expectedDistanceMatrix, actualDistanceMatrix); + ASSERT_EQ(expectedPredecessorMatrixesult, actualPredecessorMatrix); + } +} \ No newline at end of file From 24cdcf5205a0ff4f4f602fa25a26b8171990fdd5 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 29 Jan 2025 21:34:14 +0530 Subject: [PATCH 4/5] feature-test: kahn topo sort added --- Headers/0003_Graph/0003_TopologicalSort.h | 2 + .../0003_Graph/0003_TopologicalSort.cc | 52 ++++++++++++++++++- .../0014_AllPairsShortestPathsJohnson.cc | 4 ++ Tests/0003_Graph/0003_TopologicalSortTest.cc | 37 +++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) 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 From 99d69b90d48c2bbf45dac622e7586977f0f53dfc Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 29 Jan 2025 22:48:55 +0530 Subject: [PATCH 5/5] docs: doc templates updated --- .github/ISSUE_TEMPLATE/bug_report.md | 52 +++++++++++----------------- .github/PULL_REQUEST_TEMPLATE.md | 8 ++--- CODE_OF_CONDUCT.md | 27 +++++++-------- CONTRIBUTING.md | 2 +- SECURITY.md | 2 +- 5 files changed, 39 insertions(+), 52 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..bfe83ee 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,28 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' +## Bug Report ---- +### Describe the Bug +_A clear and concise description of what the bug is._ -**Describe the bug** -A clear and concise description of what the bug is. +### Steps to Reproduce +_Steps to reproduce the behavior:_ +1. Go to `path/to/file.cpp` +2. Run the test case: `./test_case_name` +3. Observe the error -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +### Expected Behavior +_A clear and concise description of what you expected to happen._ -**Expected behavior** -A clear and concise description of what you expected to happen. +### Screenshots/Outputs +_If applicable, add screenshots or log output to help explain the issue._ -**Screenshots** -If applicable, add screenshots to help explain your problem. +### Environment (please complete the following information): +- **OS:** [e.g., Windows, macOS, Linux] +- **Compiler:** [e.g., GCC 11, Clang 14, MSVC] +- **CMake Version:** [if applicable] +- **Any other relevant setup details** -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] +### Possible Fix (Optional) +_If you have an idea of how to fix it, mention it here._ -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +### Additional Context +_Add any other context about the problem here._ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d163f3f..2db2c5d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,8 @@ -# Pull Request Template +### Description -## Description - -## Type of Change +### Type of Change - [ ] Bug fix - [ ] New feature @@ -13,5 +11,5 @@ - [ ] Documentation update -## Additional Notes +### Additional Notes diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 18c9147..3f705c7 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,6 +1,6 @@ -# Contributor Covenant Code of Conduct +## Contributor Covenant Code of Conduct -## Our Pledge +### Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body @@ -12,7 +12,7 @@ and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. -## Our Standards +### Our Standards Examples of behavior that contributes to a positive environment for our community include: @@ -36,7 +36,7 @@ Examples of unacceptable behavior include: * Other conduct which could reasonably be considered inappropriate in a professional setting -## Enforcement Responsibilities +### Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in @@ -48,7 +48,7 @@ comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. -## Scope +### Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. @@ -56,22 +56,21 @@ Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -## Enforcement +### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -. +reported to the community leaders responsible for enforcement at. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. -## Enforcement Guidelines +### Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: -### 1. Correction +#### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. @@ -80,7 +79,7 @@ unprofessional or unwelcome in the community. clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. -### 2. Warning +#### 2. Warning **Community Impact**: A violation through a single incident or series of actions. @@ -92,7 +91,7 @@ includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. -### 3. Temporary Ban +#### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. @@ -103,7 +102,7 @@ private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. -### 4. Permanent Ban +#### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an @@ -112,7 +111,7 @@ individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. -## Attribution +### Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 277dc49..68a2127 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1 @@ -### This project is for academic purpose, no contributions are expected right now. +## This project is for academic purpose, no contributions are expected right now. diff --git a/SECURITY.md b/SECURITY.md index 9862d01..206769a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1 +1 @@ -# Security Policy +## Security Policy