diff --git a/Headers/0003_Graph/0005_HamiltonianPathAndCycle.h b/Headers/0003_Graph/0005_HamiltonianPathAndCycle.h new file mode 100644 index 0000000..b6f2f50 --- /dev/null +++ b/Headers/0003_Graph/0005_HamiltonianPathAndCycle.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +using namespace std; + +class HamiltonianNode +{ +public: + int data; + bool isVisited; + HamiltonianNode(int value); +}; + +class HamiltonianGraph +{ +private: + bool _isHamiltonianCyclePresent; + bool _isHamiltonianPathPresent; + int _visitedNodeCount; + HamiltonianNode* _startingNode; + map> _adjlist; + map _nodeMap; + vector _hamiltonianPath; + HamiltonianNode* MakeOrFindNode(int value); + bool IsSafe(HamiltonianNode* nodeU, HamiltonianNode* nodeV); + bool HamiltonianCycleAndPathUtil(HamiltonianNode* node); + +public: + void PushUndirectedEdge(int valueU, int valueV); + void PushSingleNode(int valueU); + void FindHamiltonianCycleAndPath(); + bool IsHamiltonianCyclePresent(); + bool IsHamiltonianPathPresent(); + vector GetHamiltonianPath(); +}; \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0005_HamiltonianPathAndCycle.cc b/SourceCodes/0003_Graph/0005_HamiltonianPathAndCycle.cc new file mode 100644 index 0000000..80c3309 --- /dev/null +++ b/SourceCodes/0003_Graph/0005_HamiltonianPathAndCycle.cc @@ -0,0 +1,112 @@ +#include "../Headers/0003_Graph/0005_HamiltonianPathAndCycle.h" + +using namespace std; + +HamiltonianNode::HamiltonianNode(int value) +{ + this->data = value; + this->isVisited = false; +} + +// HamiltonianGraph Private Member Methods +HamiltonianNode* HamiltonianGraph::MakeOrFindNode(int value) +{ + HamiltonianNode* node = nullptr; + if (this->_nodeMap.find(value) == this->_nodeMap.end()) + { + node = new HamiltonianNode(value); + this->_nodeMap[value] = node; + } + else + { + node = this->_nodeMap[value]; + } + return node; +} + +bool HamiltonianGraph::IsSafe(HamiltonianNode* nodeU, HamiltonianNode* nodeV) +{ + if (this->_adjlist[nodeU].find(nodeV) == this->_adjlist[nodeU].end()) + { + return false; + } + if (nodeV->isVisited == true) + { + return false; + } + return true; +} + +bool HamiltonianGraph::HamiltonianCycleAndPathUtil(HamiltonianNode* nodeU) +{ + if (this->_visitedNodeCount == this->_nodeMap.size()) + { + if (this->_adjlist[nodeU].find(this->_startingNode) != this->_adjlist[nodeU].end()) + { + this->_isHamiltonianCyclePresent = true; + this->_isHamiltonianPathPresent = true; + return true; + } + this->_isHamiltonianPathPresent = true; + return false; + } + for (auto& nodeV : this->_adjlist[nodeU]) + { + if (this->IsSafe(nodeU, nodeV)) + { + this->_hamiltonianPath.push_back(nodeV->data); + nodeV->isVisited = true; + this->_visitedNodeCount++; + if (this->HamiltonianCycleAndPathUtil(nodeV)) + { + return true; + } + this->_visitedNodeCount--; + nodeV->isVisited = false; + this->_hamiltonianPath.pop_back(); + } + } + return false; +} + +// HamiltonianGraph Public Member Methods +void HamiltonianGraph::PushUndirectedEdge(int valueU, int valueV) +{ + HamiltonianNode* nodeU = this->MakeOrFindNode(valueU); + HamiltonianNode* nodeV = this->MakeOrFindNode(valueV); + + this->_adjlist[nodeU].insert(nodeV); + this->_adjlist[nodeV].insert(nodeU); +} + +void HamiltonianGraph::PushSingleNode(int valueU) +{ + HamiltonianNode* nodeU = this->MakeOrFindNode(valueU); +} + +void HamiltonianGraph::FindHamiltonianCycleAndPath() +{ + this->_isHamiltonianCyclePresent = false; + this->_isHamiltonianPathPresent = false; + this->_hamiltonianPath = {}; + this->_startingNode = this->_nodeMap[0]; + this->_hamiltonianPath.push_back(this->_startingNode->data); + this->_startingNode->isVisited = true; + this->_visitedNodeCount = 1; + this->HamiltonianCycleAndPathUtil(this->_startingNode); +} + +bool HamiltonianGraph::IsHamiltonianCyclePresent() +{ + return this->_isHamiltonianCyclePresent; +} + +bool HamiltonianGraph::IsHamiltonianPathPresent() +{ + return this->_isHamiltonianPathPresent; +} + +vector HamiltonianGraph::GetHamiltonianPath() +{ + return this->_hamiltonianPath; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index 9df817b..39f75fb 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -4,6 +4,7 @@ set(0003GRAPH_SOURCES 0002_DepthFirstSearch.cc 0003_TopologicalSort.cc 0004_StronglyConnectedComponents.cc + 0005_HamiltonianPathAndCycle.cc ) # Create a library target diff --git a/Tests/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index 8e32a97..6faf4e5 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -10,7 +10,7 @@ class UnitTestHelper { public: template - string VerifyVectorResult(vector vector) + string SerializeVectorToString(vector vector) { string result = ""; for (auto& iterator : vector) @@ -22,7 +22,7 @@ class UnitTestHelper } template - string VerifyVectorResult(vector> vector) + string SerializeVectorToString(vector> vector) { string result = ""; for (auto& iterator : vector) @@ -38,7 +38,7 @@ class UnitTestHelper } template - string VerifyVectorResult(vector>> vector) + string SerializeVectorToString(vector>> vector) { string result = ""; for (auto& iterator : vector) @@ -54,7 +54,7 @@ class UnitTestHelper } template - string VerifyVectorResult(vector> vector) + string SerializeVectorToString(vector> vector) { string result = ""; for (auto& iterator : vector) @@ -107,4 +107,33 @@ class UnitTestHelper return data; } + + template + bool NormalizeCyclesAnCompare(vector data1, vector data2) + { + if (data1.size() != data2.size()) + { + return false; + } + + // Normalized rotation of cycle 1 + vector normalizedCycle1(data1); + auto minIterator1 = min_element(normalizedCycle1.begin(), normalizedCycle1.end()); + rotate(normalizedCycle1.begin(), minIterator1, normalizedCycle1.end()); + + // Normalized rotation of cycle 2 + vector normalizedCycle2(data2); + auto minIterator2 = min_element(normalizedCycle2.begin(), normalizedCycle2.end()); + rotate(normalizedCycle2.begin(), minIterator2, normalizedCycle2.end()); + + // Check clock wise + if (normalizedCycle1 == normalizedCycle2) + { + return true; + } + + // Check counter clock wise + reverse(normalizedCycle2.begin() + 1, normalizedCycle2.end()); + return (normalizedCycle1 == normalizedCycle2); + } }; \ No newline at end of file diff --git a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc index 65a5090..58bd385 100644 --- a/Tests/0002_Tree/0001_BinarySearchTreeTest.cc +++ b/Tests/0002_Tree/0001_BinarySearchTreeTest.cc @@ -15,7 +15,7 @@ namespace BinarySearchTreeTest bst.InsertNode(60); - string actualResult = unitTestHelper.VerifyVectorResult(bst.GetRecursiveInorderTravesalResult()); + string actualResult = unitTestHelper.SerializeVectorToString(bst.GetRecursiveInorderTravesalResult()); string expectedResult = "30 50 60"; EXPECT_EQ(actualResult, expectedResult); @@ -28,7 +28,7 @@ namespace BinarySearchTreeTest bst.InsertNode(30); bst.InsertNode(60); - string actualResult = unitTestHelper.VerifyVectorResult(bst.GetRecursivePreorderTravesalResult()); + string actualResult = unitTestHelper.SerializeVectorToString(bst.GetRecursivePreorderTravesalResult()); string expectedResult = "50 30 60"; EXPECT_EQ(actualResult, expectedResult); @@ -41,7 +41,7 @@ namespace BinarySearchTreeTest bst.InsertNode(30); bst.InsertNode(60); - string actualResult = unitTestHelper.VerifyVectorResult(bst.GetRecursivePostorderTravesalResult()); + string actualResult = unitTestHelper.SerializeVectorToString(bst.GetRecursivePostorderTravesalResult()); string expectedResult = "30 60 50"; EXPECT_EQ(actualResult, expectedResult); @@ -55,7 +55,7 @@ namespace BinarySearchTreeTest bst.InsertNode(60); - string actualResult = unitTestHelper.VerifyVectorResult(bst.GetMorrisInorderTraversalResult()); + string actualResult = unitTestHelper.SerializeVectorToString(bst.GetMorrisInorderTraversalResult()); string expectedResult = "30 50 60"; EXPECT_EQ(actualResult, expectedResult); @@ -69,7 +69,7 @@ namespace BinarySearchTreeTest bst.InsertNode(60); - string actualResult = unitTestHelper.VerifyVectorResult(bst.GetMorrisPreorderTraversalResult()); + string actualResult = unitTestHelper.SerializeVectorToString(bst.GetMorrisPreorderTraversalResult()); string expectedResult = "50 30 60"; EXPECT_EQ(actualResult, expectedResult); @@ -83,7 +83,7 @@ namespace BinarySearchTreeTest bst.InsertNode(60); - string actualResult = unitTestHelper.VerifyVectorResult(bst.GetMorrisPostorderTraversalResult()); + string actualResult = unitTestHelper.SerializeVectorToString(bst.GetMorrisPostorderTraversalResult()); string expectedResult = "30 60 50"; EXPECT_EQ(actualResult, expectedResult); diff --git a/Tests/0003_Graph/0001_BreadthFirstSearchTest.cc b/Tests/0003_Graph/0001_BreadthFirstSearchTest.cc index e24870f..bcc0650 100644 --- a/Tests/0003_Graph/0001_BreadthFirstSearchTest.cc +++ b/Tests/0003_Graph/0001_BreadthFirstSearchTest.cc @@ -25,7 +25,7 @@ namespace BreadthFirstSearchTest graph.BFS(1); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowBFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowBFSResult()); string expectedResult = "1(0) 2(1) 3(1) 4(2) 5(2) 6(2) 7(3) 8(3)"; EXPECT_EQ(actualResult, expectedResult); } @@ -38,7 +38,7 @@ namespace BreadthFirstSearchTest graph.BFS(1); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowBFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowBFSResult()); string expectedResult = "1(0) 2(1)"; EXPECT_EQ(actualResult, expectedResult); } diff --git a/Tests/0003_Graph/0002_DepthFirstSearchTest.cc b/Tests/0003_Graph/0002_DepthFirstSearchTest.cc index 3fd7841..c5bba61 100644 --- a/Tests/0003_Graph/0002_DepthFirstSearchTest.cc +++ b/Tests/0003_Graph/0002_DepthFirstSearchTest.cc @@ -21,7 +21,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,8) 2(2,7) 3(9,12) 4(4,5) 5(3,6) 6(10,11)"; EXPECT_EQ(actualResult, expectedResult); } @@ -35,7 +35,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,2)"; EXPECT_EQ(actualResult, expectedResult); } @@ -49,7 +49,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,4) 2(2,3) 3(5,8) 4(6,7)"; EXPECT_EQ(actualResult, expectedResult); } @@ -64,7 +64,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,6) 2(2,5) 3(3,4)"; EXPECT_EQ(actualResult, expectedResult); } @@ -92,7 +92,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,32) 2(2,29) 3(30,31) 4(3,28) 5(4,27) 6(5,26) 7(6,25) 8(7,24) 9(8,23) 10(9,22) 11(10,21) 12(11,20) 13(12,19) 14(13,18) 15(14,17) 16(15,16)"; EXPECT_EQ(actualResult, expectedResult); } @@ -108,7 +108,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,2) 2(3,4) 3(5,6)"; EXPECT_EQ(actualResult, expectedResult); } @@ -125,7 +125,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,8) 2(2,7) 3(3,4) 4(5,6)"; EXPECT_EQ(actualResult, expectedResult); } @@ -150,7 +150,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,8) 2(2,7) 3(3,6) 4(4,5)"; EXPECT_EQ(actualResult, expectedResult); } @@ -169,7 +169,7 @@ namespace DepthFirstSearchTest graph.DFS(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowDFSResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowDFSResult()); string expectedResult = "1(1,6) 2(2,5) 3(3,4)"; EXPECT_EQ(actualResult, expectedResult); } diff --git a/Tests/0003_Graph/0003_TopologicalSortTest.cc b/Tests/0003_Graph/0003_TopologicalSortTest.cc index 4eea735..b717108 100644 --- a/Tests/0003_Graph/0003_TopologicalSortTest.cc +++ b/Tests/0003_Graph/0003_TopologicalSortTest.cc @@ -23,7 +23,7 @@ namespace TopologicalSortTest graph.TopologicalSort(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowTopologicalSortResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowTopologicalSortResult()); string expectedResult = "9(17,18) 6(11,16) 7(12,15) 8(13,14) 5(9,10) 1(1,8) 4(6,7) 2(2,5) 3(3,4)"; EXPECT_EQ(actualResult, expectedResult); @@ -42,7 +42,7 @@ namespace TopologicalSortTest graph.PushDirectedEdge(6, 7); graph.TopologicalSort(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowTopologicalSortResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowTopologicalSortResult()); string expectedResult = "1(1,14) 3(12,13) 2(2,11) 4(3,10) 5(4,9) 6(5,8) 7(6,7)"; EXPECT_EQ(actualResult, expectedResult); @@ -57,7 +57,7 @@ namespace TopologicalSortTest graph.PushDirectedEdge(5, 6); graph.TopologicalSort(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowTopologicalSortResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowTopologicalSortResult()); string expectedResult = "5(9,12) 6(10,11) 3(5,8) 4(6,7) 1(1,4) 2(2,3)"; EXPECT_EQ(actualResult, expectedResult); @@ -72,7 +72,7 @@ namespace TopologicalSortTest graph.PushDirectedEdge(3, 4); graph.TopologicalSort(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowTopologicalSortResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowTopologicalSortResult()); string expectedResult = "2(7,8) 1(1,6) 3(2,5) 4(3,4)"; EXPECT_EQ(actualResult, expectedResult); @@ -85,7 +85,7 @@ namespace TopologicalSortTest graph.PushSingleNode(1); graph.TopologicalSort(); - string actualResult = unitTestHelper.VerifyVectorResult(graph.ShowTopologicalSortResult()); + string actualResult = unitTestHelper.SerializeVectorToString(graph.ShowTopologicalSortResult()); string expectedResult = "1(1,2)"; EXPECT_EQ(actualResult, expectedResult); diff --git a/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc b/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc new file mode 100644 index 0000000..3dda0b4 --- /dev/null +++ b/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc @@ -0,0 +1,33 @@ +#include +#include "../Headers/0003_Graph/0005_HamiltonianPathAndCycle.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace HamiltonianPathAndCycleTest +{ + UnitTestHelper unitTestHelper; + + TEST(HamiltonianCycleAndPathTest, ShowResult) + { + HamiltonianGraph graph; + + graph.PushUndirectedEdge(0, 1); + graph.PushUndirectedEdge(0, 3); + graph.PushUndirectedEdge(1, 2); + graph.PushUndirectedEdge(1, 3); + graph.PushUndirectedEdge(1, 4); + graph.PushUndirectedEdge(2, 4); + graph.PushUndirectedEdge(3, 4); + + graph.FindHamiltonianCycleAndPath(); + + bool isHamiltonianCyclePresent = graph.IsHamiltonianCyclePresent(); + bool isHamiltonianPathPresent = graph.IsHamiltonianPathPresent(); + + vector hamiltonianPathActualResult = graph.GetHamiltonianPath(); + vector hamiltonianPathExpectedResult = { 4, 3, 0, 1, 2 }; + + ASSERT_TRUE(isHamiltonianCyclePresent); + ASSERT_TRUE(isHamiltonianPathPresent); + ASSERT_TRUE(unitTestHelper.NormalizeCyclesAnCompare(hamiltonianPathActualResult, hamiltonianPathExpectedResult)); + } +} \ No newline at end of file diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index b43d3d3..e58a3c7 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable( 0002_DepthFirstSearchTest.cc 0003_TopologicalSortTest.cc 0004_StronglyConnectedComponentsTest.cc + 0005_HamiltonianPathAndCycleTest.cc ) target_link_libraries(