2020-08-08 20:28:50 +08:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* \file
|
|
|
|
* \brief [Breadth First Search Algorithm
|
|
|
|
* (Breadth First Search)](https://en.wikipedia.org/wiki/Breadth-first_search)
|
|
|
|
*
|
2020-10-23 11:43:40 +08:00
|
|
|
* \author [Ayaan Khan](https://github.com/ayaankhan98)
|
2020-10-23 11:43:48 +08:00
|
|
|
* \author [Aman Kumar Pandey](https://github.com/gpamangkp)
|
2020-08-08 20:28:50 +08:00
|
|
|
*
|
2020-10-21 12:55:43 +08:00
|
|
|
*
|
2020-08-08 20:28:50 +08:00
|
|
|
* \details
|
|
|
|
* Breadth First Search also quoted as BFS is a Graph Traversal Algorithm.
|
|
|
|
* Time Complexity O(|V| + |E|) where V are the number of vertices and E
|
|
|
|
* are the number of edges in the graph.
|
|
|
|
*
|
|
|
|
* Applications of Breadth First Search are
|
|
|
|
*
|
|
|
|
* 1. Finding shortest path between two vertices say u and v, with path
|
|
|
|
* length measured by number of edges (an advantage over depth first
|
|
|
|
* search algorithm)
|
|
|
|
* 2. Ford-Fulkerson Method for computing the maximum flow in a flow network.
|
|
|
|
* 3. Testing bipartiteness of a graph.
|
|
|
|
* 4. Cheney's Algorithm, Copying garbage collection.
|
|
|
|
*
|
|
|
|
* And there are many more...
|
|
|
|
*
|
|
|
|
* <h4>working</h4>
|
|
|
|
* In the implementation below we first created a graph using the adjacency
|
|
|
|
* list representation of graph.
|
|
|
|
* Breadth First Search Works as follows
|
|
|
|
* it requires a vertex as a start vertex, Start vertex is that vertex
|
|
|
|
* from where you want to start traversing the graph.
|
|
|
|
* We maintain a bool array or a vector to keep track of the vertices
|
|
|
|
* which we have visited so that we do not traverse the visited vertices
|
|
|
|
* again and again and eventually fall into an infinite loop. Along with this
|
|
|
|
* boolen array we use a Queue.
|
|
|
|
*
|
|
|
|
* 1. First we mark the start vertex as visited.
|
|
|
|
* 2. Push this visited vertex in the Queue.
|
|
|
|
* 3. while the queue is not empty we repeat the following steps
|
|
|
|
*
|
|
|
|
* 1. Take out an element from the front of queue
|
|
|
|
* 2. Explore the adjacency list of this vertex
|
|
|
|
* if element in the adjacency list is not visited then we
|
|
|
|
* push that element into the queue and mark this as visited
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
|
|
#include <queue>
|
|
|
|
#include <vector>
|
2020-10-21 12:55:43 +08:00
|
|
|
#include <map>
|
|
|
|
#include <list>
|
|
|
|
#include <string>
|
|
|
|
|
2020-10-23 11:43:27 +08:00
|
|
|
/**
|
|
|
|
* \namespace graph
|
|
|
|
* \brief Graph algorithms
|
|
|
|
*/
|
2020-10-23 11:00:13 +08:00
|
|
|
namespace graph{
|
|
|
|
/* Class Graph definition */
|
|
|
|
template<typename T>
|
|
|
|
class Graph{
|
2020-10-21 12:55:43 +08:00
|
|
|
/**
|
2020-10-23 11:00:13 +08:00
|
|
|
* adjacency_list maps every vertex to the list of its neighbours in the order
|
|
|
|
* in which they are added.
|
2020-10-21 12:55:43 +08:00
|
|
|
*/
|
2020-10-23 11:00:13 +08:00
|
|
|
std::map<T,std::list<T> > adjacency_list;
|
|
|
|
public:
|
|
|
|
Graph(){};
|
|
|
|
void add_edge(T u,T v, bool bidir=true){
|
|
|
|
/**
|
|
|
|
* add_edge(u,v,bidir) is used to add an edge between node u and node v
|
|
|
|
* by default , bidir is made true , i.e graph is bidirectional .
|
|
|
|
* It means if edge(u,v) is added then u-->v and v-->u both edges exist.
|
|
|
|
*
|
|
|
|
* to make the graph unidirectional pass the third parameter of add_edge as
|
|
|
|
* false which will
|
|
|
|
*/
|
|
|
|
adjacency_list[u].push_back(v); // u-->v edge added
|
|
|
|
if(bidir==true){
|
|
|
|
// if graph is bidirectional
|
|
|
|
adjacency_list[v].push_back(u); // v-->u edge added
|
2020-08-08 20:28:50 +08:00
|
|
|
}
|
2020-10-21 12:55:43 +08:00
|
|
|
}
|
2020-10-23 11:00:13 +08:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this function performs the breadth first search on graph and return a
|
|
|
|
* mapping which maps the nodes to a boolean value representing whether the
|
|
|
|
* node was traversed or not.
|
|
|
|
*/
|
|
|
|
std::map<T,bool> breadth_first_search(T src){
|
|
|
|
/// mapping to keep track of all visited nodes
|
|
|
|
std::map<T,bool> visited;
|
|
|
|
/// initialise every possible vertex to map to false
|
|
|
|
/// initially none of the vertices are unvisited
|
|
|
|
for(auto const &adjlist: adjacency_list){
|
|
|
|
visited[adjlist.first]=false;
|
|
|
|
for(auto const &node:adjacency_list[adjlist.first]){
|
|
|
|
visited[node]=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// queue to store the nodes which are yet to be traversed
|
|
|
|
std::queue<T> tracker;
|
|
|
|
|
|
|
|
/// push the source vertex to queue to begin traversing
|
|
|
|
tracker.push(src);
|
|
|
|
///mark the source vertex as visited
|
|
|
|
visited[src]=true;
|
|
|
|
while(!tracker.empty()){
|
|
|
|
/// traverse the graph till no connected vertex are left
|
|
|
|
/// extract a node from queue for further traversal
|
|
|
|
T node = tracker.front();
|
|
|
|
/// remove the node from the queue
|
|
|
|
tracker.pop();
|
|
|
|
for(T const &neighbour : adjacency_list[node]){
|
|
|
|
/// check every vertex connected to the node which are still unvisited
|
|
|
|
if(!visited[neighbour]){
|
|
|
|
/// if the neighbour is unvisited , push it into the queue
|
|
|
|
tracker.push(neighbour);
|
|
|
|
/// mark the neighbour as visited
|
|
|
|
visited[neighbour]=true;
|
|
|
|
}
|
2020-10-21 12:55:43 +08:00
|
|
|
}
|
|
|
|
}
|
2020-10-23 11:00:13 +08:00
|
|
|
return visited;
|
2020-10-21 12:55:43 +08:00
|
|
|
}
|
2020-10-23 11:00:13 +08:00
|
|
|
};
|
|
|
|
/* Class definition ends */
|
|
|
|
}
|
|
|
|
///Namespace definition over
|
|
|
|
|
2020-08-08 20:28:50 +08:00
|
|
|
|
2020-09-19 01:34:18 +08:00
|
|
|
/** Test function */
|
|
|
|
static void tests() {
|
2020-08-08 20:28:50 +08:00
|
|
|
/// Test 1 Begin
|
2020-10-23 11:00:13 +08:00
|
|
|
graph::Graph<int> g;
|
2020-10-21 12:55:43 +08:00
|
|
|
std::map<int,bool> correct_result;
|
|
|
|
g.add_edge(0,1);
|
|
|
|
g.add_edge(1,2);
|
|
|
|
g.add_edge(2,3);
|
|
|
|
correct_result[0]=true;
|
|
|
|
correct_result[1]=true;
|
|
|
|
correct_result[2]=true;
|
|
|
|
correct_result[3]=true;
|
|
|
|
|
|
|
|
std::map<int,bool> returned_result = g.breadth_first_search(2);
|
|
|
|
|
|
|
|
assert(returned_result==correct_result);
|
2020-08-08 20:28:50 +08:00
|
|
|
std::cout << "Test 1 Passed..." << std::endl;
|
|
|
|
|
|
|
|
/// Test 2 Begin
|
2020-10-21 12:55:43 +08:00
|
|
|
returned_result = g.breadth_first_search(0);
|
2020-10-23 11:00:13 +08:00
|
|
|
|
2020-10-21 12:55:43 +08:00
|
|
|
assert(returned_result==correct_result);
|
2020-08-08 20:28:50 +08:00
|
|
|
std::cout << "Test 2 Passed..." << std::endl;
|
|
|
|
|
|
|
|
/// Test 3 Begins
|
2020-10-23 11:00:13 +08:00
|
|
|
graph::Graph<std::string> g2;
|
2020-10-21 12:55:43 +08:00
|
|
|
|
|
|
|
g2.add_edge("Gorakhpur","Lucknow",false);
|
|
|
|
g2.add_edge("Gorakhpur","Kanpur",false);
|
|
|
|
g2.add_edge("Lucknow","Agra",false);
|
|
|
|
g2.add_edge("Kanpur","Agra",false);
|
|
|
|
g2.add_edge("Lucknow","Prayagraj",false);
|
|
|
|
g2.add_edge("Agra","Noida",false);
|
|
|
|
|
|
|
|
std::map<std::string,bool> correct_res;
|
|
|
|
std::map<std::string,bool> returned_res=g2.breadth_first_search("Kanpur");
|
|
|
|
correct_res["Gorakhpur"]=false;
|
|
|
|
correct_res["Lucknow"]=false;
|
|
|
|
correct_res["Kanpur"]=true;
|
|
|
|
correct_res["Agra"]=true;
|
|
|
|
correct_res["Prayagraj"]=false;
|
|
|
|
correct_res["Noida"]=true;
|
|
|
|
assert(correct_res==returned_res);
|
2020-08-08 20:28:50 +08:00
|
|
|
std::cout << "Test 3 Passed..." << std::endl;
|
2020-10-21 12:55:43 +08:00
|
|
|
|
2020-08-08 20:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Main function */
|
|
|
|
int main() {
|
|
|
|
tests();
|
2020-10-21 13:34:34 +08:00
|
|
|
size_t edges = 0;
|
2020-08-08 20:28:50 +08:00
|
|
|
std::cout << "Enter the number of edges: ";
|
|
|
|
std::cin >> edges;
|
|
|
|
|
2020-10-23 11:00:13 +08:00
|
|
|
graph::Graph<int> g;
|
2020-08-08 20:28:50 +08:00
|
|
|
|
|
|
|
std::cout << "Enter space-separated pairs of vertices that form edges: "
|
|
|
|
<< std::endl;
|
|
|
|
while (edges--) {
|
|
|
|
int u = 0, v = 0;
|
|
|
|
std::cin >> u >> v;
|
2020-10-21 13:34:34 +08:00
|
|
|
g.add_edge(u,v);
|
2020-08-08 20:28:50 +08:00
|
|
|
}
|
|
|
|
|
2020-10-21 13:34:34 +08:00
|
|
|
g.breadth_first_search(0);
|
2020-08-08 20:28:50 +08:00
|
|
|
return 0;
|
|
|
|
}
|