Modified the source for wider range of inputs

1. Replaced the namespace with a generic class Graph
2. Created add edge function to account for both directional and bidirectional graph
3. test case to include string nodes also
This commit is contained in:
gpamangkp 2020-10-21 10:25:43 +05:30
parent 234a29939a
commit b5cbf0e84a

View File

@ -6,6 +6,7 @@
* *
* \author [Ayaan Khan](http://github.com/ayaankhan98) * \author [Ayaan Khan](http://github.com/ayaankhan98)
* *
*
* \details * \details
* Breadth First Search also quoted as BFS is a Graph Traversal Algorithm. * 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 * Time Complexity O(|V| + |E|) where V are the number of vertices and E
@ -48,132 +49,127 @@
#include <iostream> #include <iostream>
#include <queue> #include <queue>
#include <vector> #include <vector>
#include <map>
#include <list>
#include <string>
/**
* \namespace graph
* \brief Graph algorithms
*/
namespace graph {
/** /* Class Graph definition */
* \brief Representation of the graph as an adjacency list. template<typename T>
* class Graph{
* For every vertex, there is a list of its neighbors in the order in which /**
* they were added to the graph. By default, the edges are directed, but * adjacency_list maps every vertex to the list of its neighbours in the order
* an undirected graph can be represented simply by storing each each as * in which they are added.
* two directed edges in both directions. */
*/ std::map<T,std::list<T> > adjacency_list;
using adjacency_list = std::vector<std::vector<int>>; public:
Graph(){};
/** void add_edge(T u,T v, bool bidir=true){
* \brief /**
* Adds a directed edge from vertex u to vertex v. * 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 .
* @param graph Adjacency list representation of graph * It means if edge(u,v) is added then u-->v and v-->u both edges exist.
* @param u first vertex *
* @param v second vertex * to make the graph unidirectional pass the third parameter of add_edge as
* * false which will
*/ */
void add_directed_edge(adjacency_list *graph, int u, int v) { adjacency_list[u].push_back(v); // u-->v edge added
(*graph)[u].push_back(v); if(bidir==true){
} // if graph is bidirectional
adjacency_list[v].push_back(u); // v-->u edge added
/** }
* \brief
* Adds an undirected edge from vertex u to vertex v.
* Essentially adds too directed edges to the adjacency list reprsentation
* of the graph.
*
* @param graph Adjacency list representation of graph
* @param u first vertex
* @param v second vertex
*
*/
void add_undirected_edge(adjacency_list *graph, int u, int v) {
add_directed_edge(graph, u, v);
add_directed_edge(graph, v, u);
}
/**
* \brief
* Function performs the breadth first search algorithm over the graph
*
* @param graph Adjacency list representation of graph
* @param start vertex from where traversing starts
* @returns a binary vector indicating which vertices were visited during the
* search.
*
*/
std::vector<bool> breadth_first_search(const adjacency_list &graph, int start) {
/// vector to keep track of visited vertices
std::vector<bool> visited(graph.size(), false);
/// queue that stores vertices that need to be further explored
std::queue<int> tracker;
/// mark the starting vertex as visited
visited[start] = true;
tracker.push(start);
while (!tracker.empty()) {
size_t vertex = tracker.front();
tracker.pop();
for (auto x : graph[vertex]) {
/// if the vertex is not visited then mark it as visited
/// and push it to the queue
if (!visited[x]) {
visited[x] = true;
tracker.push(x);
}
}
} }
return visited; /**
} * 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){
std::map<T,bool> tracker;
} // namespace graph for(auto adjlist: adjacency_list){
tracker[adjlist.first]=false;
for(auto node:adjacency_list[adjlist.first]){
tracker[node]=false;
}
}
std::queue<T> q;
q.push(src);
tracker[src]=true;
while(!q.empty()){
T node = q.front();
q.pop();
for(T neighbour : adjacency_list[node]){
if(!tracker[neighbour]){
q.push(neighbour);
tracker[neighbour]=true;
}
}
}
return tracker;
}
};
/** Test function */ /** Test function */
static void tests() { static void tests() {
/// Test 1 Begin /// Test 1 Begin
graph::adjacency_list graph(4, std::vector<int>()); Graph<int> g;
graph::add_undirected_edge(&graph, 0, 1); std::map<int,bool> correct_result;
graph::add_undirected_edge(&graph, 1, 2); g.add_edge(0,1);
graph::add_undirected_edge(&graph, 2, 3); 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::vector<bool> returned_result = graph::breadth_first_search(graph, 2); std::map<int,bool> returned_result = g.breadth_first_search(2);
std::vector<bool> correct_result = {true, true, true, true};
assert(std::equal(correct_result.begin(), correct_result.end(), assert(returned_result==correct_result);
returned_result.begin()));
std::cout << "Test 1 Passed..." << std::endl; std::cout << "Test 1 Passed..." << std::endl;
/// Test 2 Begin /// Test 2 Begin
returned_result = graph::breadth_first_search(graph, 0); returned_result = g.breadth_first_search(0);
assert(std::equal(correct_result.begin(), correct_result.end(), assert(returned_result==correct_result);
returned_result.begin()));
std::cout << "Test 2 Passed..." << std::endl; std::cout << "Test 2 Passed..." << std::endl;
/// Test 3 Begins /// Test 3 Begins
graph.clear(); // 0-> Gorakhpur
graph.resize(6); // 1-> Lucknow
graph::add_directed_edge(&graph, 0, 1); // 2-> Kanpur
graph::add_directed_edge(&graph, 0, 2); // 3-> Agra
graph::add_directed_edge(&graph, 1, 3); // 4-> Prayagraj
graph::add_directed_edge(&graph, 2, 3); // 5-> Noida
graph::add_directed_edge(&graph, 1, 4); Graph<std::string> g2;
graph::add_directed_edge(&graph, 3, 5);
returned_result = graph::breadth_first_search(graph, 2); g2.add_edge("Gorakhpur","Lucknow",false);
correct_result = {false, false, true, true, false, true}; 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);
assert(std::equal(correct_result.begin(), correct_result.end(), std::map<std::string,bool> correct_res;
returned_result.begin())); 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;
for(auto x: returned_res){
std::cout<<x.first<<" : "<<x.second<<std::endl;
}
assert(correct_res==returned_res);
std::cout << "Test 3 Passed..." << std::endl; std::cout << "Test 3 Passed..." << std::endl;
} }
/** Main function */ /** Main function */
int main() { int main() {
tests(); tests();
/*
size_t vertices = 0, edges = 0; size_t vertices = 0, edges = 0;
std::cout << "Enter the number of vertices: "; std::cout << "Enter the number of vertices: ";
std::cin >> vertices; std::cin >> vertices;
@ -193,5 +189,6 @@ int main() {
} }
graph::breadth_first_search(graph, 0); graph::breadth_first_search(graph, 0);
*/
return 0; return 0;
} }