mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
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:
parent
234a29939a
commit
b5cbf0e84a
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user