You are on page 1of 24

Path Finding Algorithms- A comparison of Breadth

First Search (BFS), Dijkstra’s Algorithm

DISCRETE MATHEMATICS
A-6
SURAJ KUMAR 2K19/CO/396
SURYA KUMAR SAHANI 2K19/CO/399
ACKNOWLEDGEMENT

The success and final outcomes of this project required guidance and
research from many sources and we are extremely privileged to have got
this all along with the completion of this project. All that we have done is
only due to the aforementioned sources.
We respect and thank our teacher Mr. Ajay Kumar, for providing us an
opportunity to do this project work and giving us all the support and
guidance which made us complete the project duly. We are extremely
thankful to her, for if not for her, we would not have come across the
nooks and cranny of our project.
As always, the World Wide Web acted as a lifesaver, for all the great,
helpful articles and materials stored there that immensely aided us in
thoroughly understanding the subject matter, with all the empirical
evidence presented before us, acting as cherries on top of the cake.

In the end, we are extremely grateful for this project itself and for the
insightful knowledge we gained while working on it.

Truly, it was a wonderful experience.

Thank You!
Abstract
The project started with an aim to study the important algorithms
of Graph Theory.
In the initial period of our study, we studied a general
explanation of both algorithms. Also, we got to know the
differences between them and when to use each one. They do
the same work of finding shortest paths yet are different from
each other in both requirement and implementation.

The next thing we investigated was the weighted graphs and


the unweighted graphs, the differences between them and the
way of implementation through code. Then we proceeded our
work by studying Breadth First Search Algorithm.

In Graph theory, SSSP (Single Source Shortest Path) algorithms


solve the problem of finding the shortest path from a starting
node (source), to all other nodes inside the graph. The main
algorithms that fall under this definition are Breadth First Search
(BFS) and Dijkstra‘s algorithms.
CERTIFICATE

This is to certify that the content of this project


entitled, " Path Finding Algorithms- A comparison of
Breadth First Search (BFS), Dijkstra’s Algorithm " by
SURAJ KUMAR and SURYA KUMAR SAHANI is the
bona fide work of them submitted to Mr. AJAY
KUMAR for consideration in partial fulfilment of the
requirement of DTU, Delhi for the award of grades
for MTE components
CANDIDATE'S DECLARATION
We the undersigned solemnly declare that the project Path Finding Algorithms-
A comparison of Breadth First Search (BFS), Dijkstra’s Algorithm is based on
our own work carried out during the course of our study under the supervision of
Mr Ajay Kumar.

I. Assert the statements made and conclusions drawn are an outcome of our
research work. We further certify that

II. The work contained in the report is original and has been done by us under the
general supervision of our supervisor.

III. The work has not been submitted to any other Institution for any other
degree/diploma/certificate in this university or any other University of India or
abroad.

VI. We have followed the guidelines provided by the university in writing the
report.

V. Whenever we have used materials (data, theoretical analysis, and text) from
other sources, we have given due credit to them in the text of the report and giving
their details in the references.

Surya Kumar Sahani , Suraj Kumar


(2K19/CO/399), (2K19/CO/396)
Content
• Introduction
• General Algorithm
• Breadth First Search

Code

• Dijkstra’s Algorithm

Code

• Comparison
• Conclusion
• References and Bibliography
Introduction
What is the shortest path problem?
“In graph theory, the shortest path problem is the problem of finding a
path between two vertices (or nodes) in a graph such that the sum of the
weights of its constituent edges is minimized.”

Significance and importance of the path finding algorithms


Path finding algorithms are important because they are used in
applications like google maps, satellite navigation systems,
routing packets over the internet. The usage of pathfinding
algorithms isn’t just limited to navigation systems. The overarching
idea can be applied to other applications as well.

For example - Path-finding plays


a very significant role in many
applications such as mobile
robot navigation. A grid-based
environment can be used to
represent the navigation space
for robots in the real world, to
avoid obstacles, or to navigate
to a desired position. Efficient
route tracking architectures
coupled with proper statistical
and data analysis systems can
help generate a roughly
accurate database to tackle medical emergencies like organ
transplantation from hospital of one city to another by making
special corridors for efficient and fast transportation and thereby
reducing fatalities.
General Algorithm:
Both algorithms have the same general idea. We start from the source
node and explore the graph, node by node. In each step, we always go
to the node that is closest to the source node.
This flow chart explains the general algorithm:

As we can see, the first two steps are to initialize the distances with a
large value and to add the source node to the queue. Next, we perform
iterations until the queue becomes empty. In each iteration, we extract
a node from the queue that has the shortest distance from the source
node.
After that, we visit all the neighbours of the extracted node and check
the new distance we were able to achieve. If the new distance is better
than the old one, we update the distance of this node and push it to the
queue. Finally, the algorithm moves to perform one more iteration until
the queue becomes empty.
After the algorithm ends, we’ll have the shortest paths from the source
node to all other nodes in the graph.
However, since graphs are either weighted or unweighted, we can’t use
the exact same algorithm for both cases. Therefore, we have two
algorithms. BFS calculates the shortest paths in unweighted graphs. On
the other hand, Dijkstra’s algorithm calculates the same thing in weighted
graphs.

Now the next thing we investigated was the weighted graphs and the
unweighted graphs, the differences between them and the way of
implementation through code. We have not included theoretical
explanations of weighted and Unweighted graph to keep the study concise.

BFS Algorithm
When dealing with unweighted graphs, we always care about reducing
the number of visited edges. Therefore, we are sure that all the direct
neighbours of the source node have a distance equal to one. The next
thing that we can be sure about is that all the second neighbours of the
source node have a distance equal to two, and so on.
This idea continues to be valid until we cover all the nodes of the graph.
The only exception is if we reached a node that has been visited before.
In this case, we should ignore it. The reason is that we must have reached
it with a shorter path before.
It’s worth noting that in weighted graphs, where all edges have the same
weight, the BFS algorithm calculates the shortest paths correctly. The
reason is that it cares about reducing the number of visited edges, which
is true in case of equal weights for all edges.
Here we think about the updates that need to be done to our general
algorithm which we studied initially. The main approach we follow is to
always start from a node we reached earlier. This looks similar to the
concept of FIFO (First In First Out) that we can find in a simple queue.
Therefore, we use a simple queue with BFS. We can see that there are
no more updates that we should do to our general algorithm.

Since we’re using an ordinary queue, we have an O(1) time complexity for
push and pop operations. Therefore, the total time complexity is O(V +
E), where V is the number of vertices and E is the number of edges in the
graph.

C++ CODE AND IMPLEMENTATION:

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

void addEdge(vector<int> adj[] , int u , int v){


adj[u].push_back(v);
adj[v].push_back(u);
}

void printAdj(vector<int>adj[] , int v){


for (size_t i = 0; i < v; i++)
{
cout<<"\t "<<i<<"th vertex : ";
for(int x : adj[i]){
cout<<x<<" ";
}
cout<<endl;
}

}
void BFS(vector<int> adj[] , int s , int v){
bool visited[v];
for (size_t i = 0; i < v; i++)
{
visited[i] = false;
}
queue<int> q;
visited[s] = true;
q.push(s);
while (q.empty() == false)
{
int u = q.front();
q.pop();
cout<<u<<" ";
for(int v : adj[u]){
if (visited[v] == false)
{
visited[v] = true;
q.push(v);
}

}
}
}

int main(){
int v = 7;
vector <int>adj[v];
addEdge(adj , 0 , 1);
addEdge(adj , 0 , 2);
addEdge(adj , 2 , 3);
addEdge(adj , 3 , 4);
addEdge(adj , 4 , 5);
addEdge(adj , 4 , 6);
addEdge(adj , 5 , 6);
cout<<"Graph : {\n";
//print all the connected vertices
printAdj(adj , v);
cout<<"\t}\n";
cout<<"======================\n";
//print BFS
cout<<"BFS : ";
BFS(adj , 0 , v);

return 0;
}

Output :
Dijkstra’s Algorithm

When it comes to weighted graphs, it’s not necessary that neighbouring


nodes always have the shortest path. However, the neighbour with the
shortest edge can’t be reached by any shorter path. The reason is that
all other edges have larger weights, so going through them alone would
increase the distance.
Dijkstra’s algorithm uses this idea to come up with a greedy approach.
In each step, we choose the node with the shortest path. We fix this cost
and add this node’s neighbours to the queue. Therefore, the queue must
be able to order the nodes inside it based on the smallest cost. We can
consider using a priority queue achieve this.
We still have one problem. In unweighted graphs, when we reached a
node from a different path, we were sure that the first time should have
the shortest path. In weighted graphs, that’s not always true. If we
reached the node with a shorter path, we must update its distance and
add it to the queue. This means that the same node could be added
multiple times.
Therefore, we must always compare the cost of the extracted node with
its actual stored cost. If the extracted distance is larger than the stored
one, it means this node was added in an early stage. Later, we must
have found a shorter path and updated it. We have also added the
node again to the queue, so this extraction can be ignored safely.
Since we’re visiting each nodes’ neighbors only once, we’re visiting edges
only once as well. Also, we can use a priority queue that has a time
complexity of O(logn) for push and pop operations. Therefore, the total
time complexity is O(V + E*log(V)).
C++ CODE AND IMPLEMENTATION:
#include <limits.h>
#include <stdio.h>

// Number of vertices in the graph


#define V 9

// A utility function to find the vertex with minimum distance value, from
// the set of vertices not yet included in shortest path tree
int minDistance(int dist[], bool sptSet[])
{
// Initialize min value
int min = INT_MAX, min_index;

for (int v = 0; v < V; v++)


if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;

return min_index;
}

// A utility function to print the constructed distance array


void printSolution(int dist[])
{
printf("Vertex \t\t Distance from Source\n");
for (int i = 0; i < V; i++)
printf("%d \t\t %d\n", i, dist[i]);
}

// Function that implements Dijkstra's single source shortest path algorithm


// for a graph represented using adjacency matrix representation
void dijkstra(int graph[V][V], int src)
{
int dist[V]; // The output array. dist[i] will hold the shortest
// distance from src to i

bool sptSet[V]; // sptSet[i] will be true if vertex i is included in shortest


// path tree or shortest distance from src to i is finalized

// Initialize all distances as INFINITE and stpSet[] as false


for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;

// Distance of source vertex from itself is always 0


dist[src] = 0;

// Find shortest path for all vertices


for (int count = 0; count < V - 1; count++) {
// Pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to src in the first iteration.
int u = minDistance(dist, sptSet);

// Mark the picked vertex as processed


sptSet[u] = true;

// Update dist value of the adjacent vertices of the picked vertex.


for (int v = 0; v < V; v++)

// Update dist[v] only if is not in sptSet, there is an edge from


// u to v, and total weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}

// print the constructed distance array


printSolution(dist);
}

// driver program to test above function


int main()
{
/* Let us create the example graph discussed above */
int graph[V][V] = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 },
{ 4, 0, 8, 0, 0, 0, 0, 11, 0 },
{ 0, 8, 0, 7, 0, 4, 0, 0, 2 },
{ 0, 0, 7, 0, 9, 14, 0, 0, 0 },
{ 0, 0, 0, 9, 0, 10, 0, 0, 0 },
{ 0, 0, 4, 14, 10, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 1, 6 },
{ 8, 11, 0, 0, 0, 0, 1, 0, 7 },
{ 0, 0, 2, 0, 0, 0, 6, 7, 0 } };

dijkstra(graph, 0);

return 0;
}

Output :
Example
Take a look at the following graph. It contains an example of applying
the BFS algorithm to a simple, unweighted graph. The letter
corresponds to the node index, while the number shows the stored
distance after performing the BFS algorithm:

We can clearly see that the algorithm visits the nodes, level by level.
First, all the neighbors are visited on level 1. Next, all the second
neighbors are visited on level 2, and so on. As a result, we’re able to
calculate the shortest path to all nodes starting from the source node .
Now, let’s take a look at the result of applying Dijkstra’s algorithm to
the weighted version of the same graph:
Although node A is one step away from the source S, Dijkstra’s algorithm
first explored node B because the edge to B has the lowest cost.
Next, from B, it found a shorter path to node A, which is the path that
the algorithm stored.
We can also note that although it’s one step away from S, we didn’t
visit C directly. The reason is that the edge between S and C has a very
large cost. Luckily, we were able to reach C from a shorter path than
the direct edge.
Comparison
The following table shows a summarized comparison between the two
algorithms:

Conclusion
In this study, we presented the general algorithm for BFS and Dijkstra’s
algorithms. Next, we explained the main similarities and differences
between the two algorithms.

After that, we took a look at the result of applying both algorithms to


unweighted and weighted versions of the same graph.
Finally, we gave a comparison between both algorithms.
Bibliography

What is difference between BFS and Dijkstra's algorithms when looking


for shortest path?

https://stackoverflow.com/questions/25449781/what-is-difference-between-
bfs-and-dijkstras-algorithms-when-looking-for-shorte/43752467

Pathfinding Algorithms
https://medium.com/swlh/pathfinding-algorithms-
6c0d4febe8fd#:~:text=Path%20finding%20algorithms%20are%20important,t
o%20other%20applications%20as%20well

Dijkstra vs BFS for shortest path


https://cs.stackexchange.com/questions/18138/dijkstra-algorithm-vs-breadth-
first-search-for-shortest-path-in-graph
THANK YOU!

You might also like