Algorithms_in_C++  1.0.0
Set of algorithms implemented in C++.
bidirectional_dijkstra.cpp File Reference

Bidirectional Dijkstra Shortest Path Algorithm More...

#include <cassert>
#include <iostream>
#include <limits>
#include <queue>
#include <utility>
#include <vector>
Include dependency graph for bidirectional_dijkstra.cpp:

Namespaces

 graph
 Graph Algorithms.
 
 bidirectional_dijkstra
 Functions for Bidirectional Dijkstra Shortest Path algorithm.
 

Functions

void graph::bidirectional_dijkstra::addEdge (std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj1, std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj2, uint64_t u, uint64_t v, uint64_t w)
 Function that add edge between two nodes or vertices of graph. More...
 
uint64_t graph::bidirectional_dijkstra::Shortest_Path_Distance (const std::vector< uint64_t > &workset_, const std::vector< std::vector< uint64_t >> &distance_)
 This function returns the shortest distance from the source to the target if there is path between vertices 's' and 't'. More...
 
int graph::bidirectional_dijkstra::Bidijkstra (std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj1, std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj2, uint64_t s, uint64_t t)
 Function runs the dijkstra algorithm for some source vertex and target vertex in the graph and returns the shortest distance of target from the source. More...
 
static void tests ()
 Function to test the provided algorithm above. More...
 
int main ()
 Main function. More...
 

Variables

constexpr int64_t INF = std::numeric_limits<int64_t>::max()
 for store the graph, the distances, and the path More...
 

Detailed Description

Bidirectional Dijkstra Shortest Path Algorithm

Author
Marinovksy

This is basically the same Dijkstra Algorithm but faster because it goes from the source to the target and from target to the source and stops when finding a vertex visited already by the direct search or the reverse one. Here some simulations of it: https://www.youtube.com/watch?v=DINCL5cd_w0&t=24s

Function Documentation

◆ addEdge()

void graph::bidirectional_dijkstra::addEdge ( std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *  adj1,
std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *  adj2,
uint64_t  u,
uint64_t  v,
uint64_t  w 
)

Function that add edge between two nodes or vertices of graph.

Parameters
adj1adjacency list for the direct search
adj2adjacency list for the reverse search
uany node or vertex of graph
vany node or vertex of graph
47  {
48  (*adj1)[u - 1].push_back(std::make_pair(v - 1, w));
49  (*adj2)[v - 1].push_back(std::make_pair(u - 1, w));
50  // (*adj)[v - 1].push_back(std::make_pair(u - 1, w));
51 }
T make_pair(T... args)
Here is the call graph for this function:

◆ Bidijkstra()

int graph::bidirectional_dijkstra::Bidijkstra ( std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *  adj1,
std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *  adj2,
uint64_t  s,
uint64_t  t 
)

Function runs the dijkstra algorithm for some source vertex and target vertex in the graph and returns the shortest distance of target from the source.

Parameters
adj1input graph
adj2input graph reversed
ssource vertex
ttarget vertex
Returns
shortest distance if target is reachable from source else -1 in case if target is not reachable from source.

n denotes the number of vertices in graph

setting all the distances initially to INF

creating a a vector of min heap using priority queue pq[0] contains the min heap for the direct search pq[1] contains the min heap for the reverse search

first element of pair contains the distance second element of pair contains the vertex

vector for store the nodes or vertices in the shortest path

vector for store the nodes or vertices visited

pushing the source vertex 's' with 0 distance in pq[0] min heap

marking the distance of source as 0

pushing the target vertex 't' with 0 distance in pq[1] min heap

marking the distance of target as 0

direct search

second element of pair denotes the node / vertex

first element of pair denotes the distance

for all the reachable vertex from the currently exploring vertex we will try to minimize the distance

minimizing distances

check if currentNode has already been visited

reversed search

second element of pair denotes the node / vertex

first element of pair denotes the distance

for all the reachable vertex from the currently exploring vertex we will try to minimize the distance

minimizing distances

check if currentNode has already been visited

88  {
89  /// n denotes the number of vertices in graph
90  uint64_t n = adj1->size();
91 
92  /// setting all the distances initially to INF
94 
95  /// creating a a vector of min heap using priority queue
96  /// pq[0] contains the min heap for the direct search
97  /// pq[1] contains the min heap for the reverse search
98 
99  /// first element of pair contains the distance
100  /// second element of pair contains the vertex
101  std::vector<
105  pq(2);
106  /// vector for store the nodes or vertices in the shortest path
107  std::vector<uint64_t> workset(n);
108  /// vector for store the nodes or vertices visited
109  std::vector<bool> visited(n);
110 
111  /// pushing the source vertex 's' with 0 distance in pq[0] min heap
112  pq[0].push(std::make_pair(0, s));
113 
114  /// marking the distance of source as 0
115  dist[0][s] = 0;
116 
117  /// pushing the target vertex 't' with 0 distance in pq[1] min heap
118  pq[1].push(std::make_pair(0, t));
119 
120  /// marking the distance of target as 0
121  dist[1][t] = 0;
122 
123  while (true) {
124  /// direct search
125 
126  // If pq[0].size() is equal to zero then the node/ vertex is not
127  // reachable from s
128  if (pq[0].size() == 0) {
129  break;
130  }
131  /// second element of pair denotes the node / vertex
132  uint64_t currentNode = pq[0].top().second;
133 
134  /// first element of pair denotes the distance
135  uint64_t currentDist = pq[0].top().first;
136 
137  pq[0].pop();
138 
139  /// for all the reachable vertex from the currently exploring vertex
140  /// we will try to minimize the distance
141  for (std::pair<int, int> edge : (*adj1)[currentNode]) {
142  /// minimizing distances
143  if (currentDist + edge.second < dist[0][edge.first]) {
144  dist[0][edge.first] = currentDist + edge.second;
145  pq[0].push(std::make_pair(dist[0][edge.first], edge.first));
146  }
147  }
148  // store the processed node/ vertex
149  workset.push_back(currentNode);
150 
151  /// check if currentNode has already been visited
152  if (visited[currentNode] == 1) {
153  return Shortest_Path_Distance(workset, dist);
154  }
155  visited[currentNode] = true;
156  /// reversed search
157 
158  // If pq[1].size() is equal to zero then the node/ vertex is not
159  // reachable from t
160  if (pq[1].size() == 0) {
161  break;
162  }
163  /// second element of pair denotes the node / vertex
164  currentNode = pq[1].top().second;
165 
166  /// first element of pair denotes the distance
167  currentDist = pq[1].top().first;
168 
169  pq[1].pop();
170 
171  /// for all the reachable vertex from the currently exploring vertex
172  /// we will try to minimize the distance
173  for (std::pair<int, int> edge : (*adj2)[currentNode]) {
174  /// minimizing distances
175  if (currentDist + edge.second < dist[1][edge.first]) {
176  dist[1][edge.first] = currentDist + edge.second;
177  pq[1].push(std::make_pair(dist[1][edge.first], edge.first));
178  }
179  }
180  // store the processed node/ vertex
181  workset.push_back(currentNode);
182 
183  /// check if currentNode has already been visited
184  if (visited[currentNode] == 1) {
185  return Shortest_Path_Distance(workset, dist);
186  }
187  visited[currentNode] = true;
188  }
189  return -1;
190 }
constexpr int64_t INF
for store the graph, the distances, and the path
Definition: bidirectional_dijkstra.cpp:23
uint64_t Shortest_Path_Distance(const std::vector< uint64_t > &workset_, const std::vector< std::vector< uint64_t >> &distance_)
This function returns the shortest distance from the source to the target if there is path between ve...
Definition: bidirectional_dijkstra.cpp:61
T size(T... args)
Here is the call graph for this function:

◆ main()

int main ( void  )

Main function.

Returns
0 on exit
248  {
249  tests(); // running predefined tests
250  uint64_t vertices = uint64_t();
251  uint64_t edges = uint64_t();
252  std::cout << "Enter the number of vertices : ";
253  std::cin >> vertices;
254  std::cout << "Enter the number of edges : ";
255  std::cin >> edges;
256 
261 
262  uint64_t u = uint64_t(), v = uint64_t(), w = uint64_t();
263  std::cout << "Enter the edges by three integers in this form: u v w "
264  << std::endl;
265  std::cout << "Example: if there is and edge between node 1 and node 4 with "
266  "weight 7 enter: 1 4 7, and then press enter"
267  << std::endl;
268  while (edges--) {
269  std::cin >> u >> v >> w;
270  graph::bidirectional_dijkstra::addEdge(&adj1, &adj2, u, v, w);
271  if (edges != 0) {
272  std::cout << "Enter the next edge" << std::endl;
273  }
274  }
275 
276  uint64_t s = uint64_t(), t = uint64_t();
277  std::cout
278  << "Enter the source node and the target node separated by a space"
279  << std::endl;
280  std::cout << "Example: If the source node is 5 and the target node is 6 "
281  "enter: 5 6 and press enter"
282  << std::endl;
283  std::cin >> s >> t;
284  int dist =
285  graph::bidirectional_dijkstra::Bidijkstra(&adj1, &adj2, s - 1, t - 1);
286  if (dist == -1) {
287  std::cout << "Target not reachable from source" << std::endl;
288  } else {
289  std::cout << "Shortest Path Distance : " << dist << std::endl;
290  }
291 
292  return 0;
293 }
static void tests()
Function to test the provided algorithm above.
Definition: bidirectional_dijkstra.cpp:199
void addEdge(std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj1, std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj2, uint64_t u, uint64_t v, uint64_t w)
Function that add edge between two nodes or vertices of graph.
Definition: bidirectional_dijkstra.cpp:45
int Bidijkstra(std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj1, std::vector< std::vector< std::pair< uint64_t, uint64_t >>> *adj2, uint64_t s, uint64_t t)
Function runs the dijkstra algorithm for some source vertex and target vertex in the graph and return...
Definition: bidirectional_dijkstra.cpp:86
T endl(T... args)
Here is the call graph for this function:

◆ Shortest_Path_Distance()

uint64_t graph::bidirectional_dijkstra::Shortest_Path_Distance ( const std::vector< uint64_t > &  workset_,
const std::vector< std::vector< uint64_t >> &  distance_ 
)

This function returns the shortest distance from the source to the target if there is path between vertices 's' and 't'.

Parameters
workset_vertices visited in the search
distance_vector of distances from the source to the target and from the target to the source
63  {
64  int64_t distance = INF;
65  for (uint64_t i : workset_) {
66  if (distance_[0][i] + distance_[1][i] < distance) {
67  distance = distance_[0][i] + distance_[1][i];
68  }
69  }
70  return distance;
71 }
T distance(T... args)
Here is the call graph for this function:

◆ tests()

static void tests ( )
static

Function to test the provided algorithm above.

Returns
void
199  {
200  std::cout << "Initiatinig Predefined Tests..." << std::endl;
201  std::cout << "Initiating Test 1..." << std::endl;
206  graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 1, 2, 1);
207  graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 4, 1, 2);
208  graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 2, 3, 2);
209  graph::bidirectional_dijkstra::addEdge(&adj1_1, &adj1_2, 1, 3, 5);
210 
211  uint64_t s = 1, t = 3;
212  assert(graph::bidirectional_dijkstra::Bidijkstra(&adj1_1, &adj1_2, s - 1,
213  t - 1) == 3);
214  std::cout << "Test 1 Passed..." << std::endl;
215 
216  s = 4, t = 3;
217  std::cout << "Initiating Test 2..." << std::endl;
218  assert(graph::bidirectional_dijkstra::Bidijkstra(&adj1_1, &adj1_2, s - 1,
219  t - 1) == 5);
220  std::cout << "Test 2 Passed..." << std::endl;
221 
226  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 1, 2, 4);
227  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 1, 3, 2);
228  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 2, 3, 2);
229  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 3, 2, 1);
230  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 2, 4, 2);
231  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 3, 5, 4);
232  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 5, 4, 1);
233  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 2, 5, 3);
234  graph::bidirectional_dijkstra::addEdge(&adj2_1, &adj2_2, 3, 4, 4);
235 
236  s = 1, t = 5;
237  std::cout << "Initiating Test 3..." << std::endl;
238  assert(graph::bidirectional_dijkstra::Bidijkstra(&adj2_1, &adj2_2, s - 1,
239  t - 1) == 6);
240  std::cout << "Test 3 Passed..." << std::endl;
241  std::cout << "All Test Passed..." << std::endl << std::endl;
242 }
Here is the call graph for this function:

Variable Documentation

◆ INF

constexpr int64_t INF = std::numeric_limits<int64_t>::max()
constexpr

for store the graph, the distances, and the path

for assert for io operations for variable INF for the priority_queue of distances for make_pair function