diff --git a/Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h b/Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h new file mode 100644 index 0000000..c2eccfe --- /dev/null +++ b/Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +using namespace std; + +namespace SingleSourceShortestPathDijkstra +{ + class Node + { + public: + int data; + int distance; + Node* parent; + 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: + map> _adjlist; + map _nodeMap; + map> _edgeMap; + multiset _operationalSet; + Node* MakeOrFindNode(int data); + void InitializeSingleSource(Node* sourceNode); + void Relax(Edge* edge); + void Dijkstra(Node* source); + void GetShortestPath(Node* node, vector& path); + + public: + void PushDirectedEdge(int valueU, int valueV, int weight); + void FindShortestPathDijkstra(int data); + vector GetDijkstraShortestPath(int data); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc b/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc new file mode 100644 index 0000000..138899f --- /dev/null +++ b/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc @@ -0,0 +1,113 @@ +#include "../Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h" +#include +#include +using namespace std; + +namespace SingleSourceShortestPathDijkstra +{ + Node::Node(int data) + { + this->data = data; + this->distance = INT_MAX; + this->parent = nullptr; + } + + 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::InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + iterator.second->parent = nullptr; + } + sourceNode->distance = 0; + } + + void Graph::Relax(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->Relax(edge); + } + } + } + + void Graph::GetShortestPath(Node* node, vector& path) + { + path.push_back(node->data); + if (node->parent != nullptr) + { + this->GetShortestPath(node->parent, path); + } + } + + // 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); + this->_edgeMap[nodeU].push_back(new Edge(nodeU, nodeV, weight)); + } + + void Graph::FindShortestPathDijkstra(int data) + { + Node* source = this->_nodeMap[data]; + this->Dijkstra(source); + } + + vector Graph::GetDijkstraShortestPath(int data) + { + vector path = {}; + Node* node = this->_nodeMap[data]; + this->GetShortestPath(node, path); + reverse(path.begin(), path.end()); + return path; + } +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index 5ddfee0..eb010e7 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -10,6 +10,7 @@ set(0003GRAPH_SOURCES 0008_MinimumSpanningTreePrimAlgorithm.cc 0009_SingleSourceShortestPathBellmanFord.cc 0010_DirectedAcyclicGraphShortestPath.cc + 0011_SingleSourceShortestPathDijkstra.cc ) diff --git a/Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc b/Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc new file mode 100644 index 0000000..4f0be15 --- /dev/null +++ b/Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc @@ -0,0 +1,31 @@ +#include +#include "../Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace SingleSourceShortestPathDijkstra +{ + UnitTestHelper unitTestHelper; + + // Test for Simple Graph + TEST(DijkstraTest, SimpleGraph) + { + Graph graph; + + graph.PushDirectedEdge(0, 1, 10); + graph.PushDirectedEdge(0, 3, 5); + graph.PushDirectedEdge(1, 2, 1); + graph.PushDirectedEdge(1, 3, 2); + graph.PushDirectedEdge(2, 4, 4); + graph.PushDirectedEdge(3, 1, 3); + graph.PushDirectedEdge(3, 2, 9); + graph.PushDirectedEdge(3, 4, 2); + graph.PushDirectedEdge(4, 2, 6); + graph.PushDirectedEdge(4, 0, 7); + + graph.FindShortestPathDijkstra(0); + + string expectedPath = "0 3 1 2"; + + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetDijkstraShortestPath(2)), expectedPath); + } +} \ No newline at end of file diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 66a6d5b..42d15cb 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable( 0008_MinimumSpanningTreePrimAlgorithmTest.cc 0009_SingleSourceShortestPathBellmanFordTest.cc 0010_DirectedAcyclicGraphShortestPathTest.cc + 0011_SingleSourceShortestPathDijkstraTest.cc ) target_link_libraries(