Skip to content

Commit 3d0e95b

Browse files
authored
Merge pull request #53 from Debashis08/feature-graph-implementation
Feature graph implementation
2 parents 3822fb3 + ee712db commit 3d0e95b

File tree

5 files changed

+325
-0
lines changed

5 files changed

+325
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#pragma once
2+
3+
#include<map>
4+
#include<vector>
5+
#include<set>
6+
using namespace std;
7+
8+
namespace AllPairsShortestPathsJohnson
9+
{
10+
class Node
11+
{
12+
public:
13+
int data;
14+
int distance;
15+
Node* parent;
16+
int potentialWeight;
17+
Node(int data);
18+
};
19+
20+
class Edge
21+
{
22+
public:
23+
Node* nodeU;
24+
Node* nodeV;
25+
int weight;
26+
Edge(Node* nodeU, Node* nodeV, int weight);
27+
};
28+
29+
class CompareNodeDistance
30+
{
31+
public:
32+
bool operator()(const Node* nodeU, const Node* nodeV) const
33+
{
34+
return nodeU->distance < nodeV->distance;
35+
}
36+
};
37+
38+
class Graph
39+
{
40+
private:
41+
int _noOfVertices=0;
42+
map<Node*, vector<Node*>> _adjlist;
43+
map<int, Node*> _nodeMap;
44+
vector<Edge*> _edgeList;
45+
map<Node*, vector<Edge*>> _edgeMap;
46+
map<Node*, vector<Node*>> _augmentedAdjlist;
47+
vector<Edge*> _augmentedEdgeList;
48+
multiset<Node*, CompareNodeDistance> _operationalSet;
49+
vector<vector<int>> _shortestPathMatrix;
50+
vector<vector<int>> _predecessorMatrix;
51+
Node* MakeOrFindNode(int data);
52+
void PushAugmentedDirectedEdges(Node* sourceNode, Node* nodeV, int weight);
53+
void InitializeSingleSource(Node* sourceNode);
54+
void RelaxBellmanFord(Edge* edge);
55+
bool BellmanFord(Node* source);
56+
void RelaxDijkstra(Edge* edge);
57+
void Dijkstra(Node* source);
58+
void GetShortestPath(int source, int destination, vector<int>& path);
59+
60+
public:
61+
void PushDirectedEdge(int dataU, int dataV, int weight);
62+
bool FindAllPairsShortestPathsJohnsonAlgorithm();
63+
vector<vector<int>> GetAllPairsShortestPathsDistanceMatrix();
64+
vector<vector<int>> GetAllPairsShortestPathsPathMatrix();
65+
};
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#include "../Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h"
2+
#include<climits>
3+
using namespace std;
4+
5+
namespace AllPairsShortestPathsJohnson
6+
{
7+
Node::Node(int data)
8+
{
9+
this->data = data;
10+
this->distance = INT_MAX;
11+
this->parent = nullptr;
12+
this->potentialWeight = 0;
13+
}
14+
15+
Edge::Edge(Node* nodeU, Node* nodeV, int weight)
16+
{
17+
this->nodeU = nodeU;
18+
this->nodeV = nodeV;
19+
this->weight = weight;
20+
}
21+
22+
// Graph Private Member Methods
23+
Node* Graph::MakeOrFindNode(int data)
24+
{
25+
Node* node = nullptr;
26+
if (this->_nodeMap.find(data) == this->_nodeMap.end())
27+
{
28+
node = new Node(data);
29+
this->_nodeMap[data] = node;
30+
}
31+
else
32+
{
33+
node = this->_nodeMap[data];
34+
}
35+
return node;
36+
}
37+
38+
void Graph::PushAugmentedDirectedEdges(Node* sourceNode, Node* nodeV, int weight)
39+
{
40+
this->_augmentedAdjlist[sourceNode].push_back(nodeV);
41+
this->_augmentedEdgeList.push_back(new Edge(sourceNode, nodeV, weight));
42+
}
43+
44+
void Graph::InitializeSingleSource(Node* sourceNode)
45+
{
46+
for (auto& iterator : this->_nodeMap)
47+
{
48+
iterator.second->distance = INT_MAX;
49+
iterator.second->parent = nullptr;
50+
}
51+
sourceNode->distance = 0;
52+
}
53+
54+
void Graph::RelaxBellmanFord(Edge* edge)
55+
{
56+
if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)))
57+
{
58+
edge->nodeV->distance = edge->nodeU->distance + edge->weight;
59+
edge->nodeV->parent = edge->nodeU;
60+
}
61+
}
62+
63+
bool Graph::BellmanFord(Node* source)
64+
{
65+
this->InitializeSingleSource(source);
66+
67+
for (int i = 0; i < this->_nodeMap.size() - 1; i++)
68+
{
69+
for (auto& edge : this->_augmentedEdgeList)
70+
{
71+
this->RelaxBellmanFord(edge);
72+
}
73+
}
74+
75+
for (auto& edge : this->_augmentedEdgeList)
76+
{
77+
if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))
78+
{
79+
return false;
80+
}
81+
}
82+
return true;
83+
}
84+
85+
void Graph::RelaxDijkstra(Edge* edge)
86+
{
87+
if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)))
88+
{
89+
this->_operationalSet.erase(edge->nodeV);
90+
edge->nodeV->distance = edge->nodeU->distance + edge->weight;
91+
edge->nodeV->parent = edge->nodeU;
92+
this->_operationalSet.insert(edge->nodeV);
93+
}
94+
}
95+
96+
void Graph::Dijkstra(Node* source)
97+
{
98+
this->InitializeSingleSource(source);
99+
100+
for (auto& node : this->_nodeMap)
101+
{
102+
this->_operationalSet.insert(node.second);
103+
}
104+
105+
while (!this->_operationalSet.empty())
106+
{
107+
Node* nodeU = *(this->_operationalSet.begin());
108+
this->_operationalSet.erase(nodeU);
109+
110+
for (auto& edge : this->_edgeMap[nodeU])
111+
{
112+
this->RelaxDijkstra(edge);
113+
}
114+
}
115+
}
116+
117+
void Graph::GetShortestPath(int source, int destination, vector<int>& path)
118+
{
119+
if (this->_predecessorMatrix[source - 1][destination - 1] != source)
120+
{
121+
int predecessor = this->_predecessorMatrix[source - 1][destination - 1];
122+
this->GetShortestPath(source, predecessor, path);
123+
path.push_back(predecessor);
124+
}
125+
}
126+
127+
// Graph Public Member Methods
128+
void Graph::PushDirectedEdge(int dataU, int dataV, int weight)
129+
{
130+
Node* nodeU = this->MakeOrFindNode(dataU);
131+
Node* nodeV = this->MakeOrFindNode(dataV);
132+
133+
this->_adjlist[nodeU].push_back(nodeV);
134+
Edge* edge = new Edge(nodeU, nodeV, weight);
135+
this->_edgeMap[nodeU].push_back(edge);
136+
this->_edgeList.push_back(edge);
137+
}
138+
139+
bool Graph::FindAllPairsShortestPathsJohnsonAlgorithm()
140+
{
141+
// Creating the graph G'
142+
this->_augmentedAdjlist = this->_adjlist;
143+
this->_augmentedEdgeList = this->_edgeList;
144+
Node* source = new Node(0);
145+
this->_nodeMap[0] = source;
146+
for (auto& node : this->_nodeMap)
147+
{
148+
if (node.second != source)
149+
{
150+
this->PushAugmentedDirectedEdges(source, node.second, 0);
151+
}
152+
}
153+
154+
if (this->BellmanFord(source) == false)
155+
{
156+
return false;
157+
}
158+
else
159+
{
160+
this->_nodeMap.erase(0);
161+
for (auto& node : this->_nodeMap)
162+
{
163+
node.second->potentialWeight = node.second->distance;
164+
}
165+
166+
for (auto& edge : this->_edgeList)
167+
{
168+
edge->weight = edge->weight + edge->nodeU->potentialWeight - edge->nodeV->potentialWeight;
169+
}
170+
171+
this->_noOfVertices = (int)this->_nodeMap.size();
172+
this->_shortestPathMatrix = vector<vector<int>>(this->_noOfVertices, vector<int>(this->_noOfVertices, -1));
173+
this->_predecessorMatrix = vector<vector<int>>(this->_noOfVertices, vector<int>(this->_noOfVertices, -1));
174+
for (auto& iteratorU : this->_nodeMap)
175+
{
176+
Node* nodeU = iteratorU.second;
177+
this->Dijkstra(nodeU);
178+
for (auto& iteratorV : this->_nodeMap)
179+
{
180+
Node* nodeV = iteratorV.second;
181+
this->_shortestPathMatrix[nodeU->data - 1][nodeV->data - 1] = nodeV->distance + nodeV->potentialWeight - nodeU->potentialWeight;
182+
this->_predecessorMatrix[nodeU->data - 1][nodeV->data - 1] = nodeV->parent != nullptr ? nodeV->parent->data : -1;
183+
}
184+
}
185+
return true;
186+
}
187+
}
188+
189+
vector<vector<int>> Graph::GetAllPairsShortestPathsDistanceMatrix()
190+
{
191+
return this->_shortestPathMatrix;
192+
}
193+
194+
vector<vector<int>> Graph::GetAllPairsShortestPathsPathMatrix()
195+
{
196+
vector<vector<int>> result;
197+
for (int i = 0; i < this->_noOfVertices; i++)
198+
{
199+
for (int j = 0; j < this->_noOfVertices; j++)
200+
{
201+
if (i != j)
202+
{
203+
vector<int> path = {};
204+
path.push_back(i + 1);
205+
this->GetShortestPath(i + 1, j + 1, path);
206+
path.push_back(j + 1);
207+
result.push_back(path);
208+
}
209+
}
210+
}
211+
return result;
212+
}
213+
}

SourceCodes/0003_Graph/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(0003GRAPH_SOURCES
1313
0011_SingleSourceShortestPathDijkstra.cc
1414
0012_DifferenceConstraintsShortestPaths.cc
1515
0013_AllPairsShortestPathsFloydWarshall.cc
16+
0014_AllPairsShortestPathsJohnson.cc
1617

1718
)
1819

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include<gtest/gtest.h>
2+
#include"../Headers/0003_Graph/0014_AllPairsShortestPathsJohnson.h"
3+
#include"../0000_CommonUtilities/UnitTestHelper.h"
4+
using namespace std;
5+
6+
namespace AllPairsShortestPathsJohnson
7+
{
8+
UnitTestHelper unitTestHelper;
9+
10+
TEST(JohnsonAlgorithm, SimpleGraph)
11+
{
12+
// Arrange
13+
Graph graph;
14+
vector<vector<int>> expectedDistanceMatrix =
15+
{
16+
{0, 1, -3, 2, -4},
17+
{3, 0, -4, 1, -1},
18+
{7, 4, 0, 5, 3},
19+
{2, -1, -5, 0, -2},
20+
{8, 5, 1, 6, 0},
21+
};
22+
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]";
23+
24+
// Act
25+
graph.PushDirectedEdge(1, 2, 3);
26+
graph.PushDirectedEdge(1, 3, 8);
27+
graph.PushDirectedEdge(1, 5, -4);
28+
graph.PushDirectedEdge(2, 4, 1);
29+
graph.PushDirectedEdge(2, 5, 7);
30+
graph.PushDirectedEdge(3, 2, 4);
31+
graph.PushDirectedEdge(4, 3, -5);
32+
graph.PushDirectedEdge(4, 1, 2);
33+
graph.PushDirectedEdge(5, 4, 6);
34+
35+
bool result = graph.FindAllPairsShortestPathsJohnsonAlgorithm();
36+
vector<vector<int>> actualDistanceMatrix = graph.GetAllPairsShortestPathsDistanceMatrix();
37+
string actualPredecessorMatrix = unitTestHelper.SerializeVectorToString(graph.GetAllPairsShortestPathsPathMatrix());
38+
39+
// Assert
40+
ASSERT_TRUE(result);
41+
ASSERT_EQ(expectedDistanceMatrix, actualDistanceMatrix);
42+
ASSERT_EQ(expectedPredecessorMatrixesult, actualPredecessorMatrix);
43+
}
44+
}

Tests/0003_Graph/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_executable(
2525
0011_SingleSourceShortestPathDijkstraTest.cc
2626
0012_DifferenceConstraintsShortestPathsTest.cc
2727
0013_AllPairsShortestPathsFloydWarshallTest.cc
28+
0014_AllPairsShortestPathsJohnsonTest.cc
2829
)
2930

3031
target_link_libraries(

0 commit comments

Comments
 (0)