#include <iostream>
#include <sstream>
#include <string>
#include <cassert>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <stack>
namespace Graph
{
template<typename T>
class AdjacencyList
{
public:
AdjacencyList(std::istringstream & _ss, const T & _default_val, const bool _directed = false) :
m_list(), m_val(), m_default_value(_default_val), directed(_directed)
{
using namespace std;
string edge;
while(getline(_ss, edge, ';'))
{
istringstream ss_edge(edge);
string vertex_from;
getline(ss_edge, vertex_from, ',');
istringstream ss_vertex_from(vertex_from);
int from, to;
ss_vertex_from >> from;
ss_edge >> to;
Add(from, to);
m_val[from] = m_default_value;
m_val[to] = m_default_value;
}
}
virtual ~AdjacencyList()
{
}
virtual bool Adjacent(int _x, int _y) const
{
std::map<int, std::set<int> >::const_iterator it = m_list.find(_x);
return (it->second.find(_y) != it->second.end());
}
virtual std::set<int> Neighbours(const int _x) const
{
std::set<int> s;
std::map<int, std::set<int> >::const_iterator it = m_list.find(_x);
if (it != m_list.end())
{
s = m_list.find(_x)->second;
}
return s;
}
virtual std::set<int> Parents(const int _x) const
{
using namespace std;
set<int> parents;
for (map<int, set<int> >::const_iterator it = m_list.begin(); it != m_list.end(); ++it)
{
if (it->second.find(_x) != it->second.end())
{
parents.insert(it->first);
}
}
return parents;
}
virtual bool Add(const int _x, const int _y)
{
std::pair<std::set<int>::iterator, bool> ret = m_list[_x].insert(_y);
if (directed)
{
if (m_list.count(_y) == 0)
{
m_list[_y].clear(); // Initialize with empty set
}
}
else
{
m_list[_y].insert(_x);
}
return ret.second;
}
virtual bool Delete(const int _x, const int _y)
{
m_list[_x].erase(_y);
return (m_list[_y].erase(_x) == 1 ? true : false);
}
virtual T GetValue(const int _x) const
{
typename std::map<int, T>::const_iterator it = m_val.find(_x);
if (it == m_val.end())
{
return m_default_value;
}
return it->second;
}
virtual void SetValue(int _x, const T & _val)
{
m_val[_x] = _val;
}
virtual void PrintBFS(const int _x) const
{
using namespace std;
if (m_list.find(_x) == m_list.end())
{
cout << _x << " not a vertex\n";
return;
}
queue<int> q;
set<int> visited;
q.push(_x);
size_t curr_level = 1;
bool print_newline = false;
while (!q.empty())
{
int vertex = q.front();
q.pop();
if (visited.find(vertex) == visited.end())
{
visited.insert(vertex);
cout << vertex << ", ";
set<int> n = Neighbours(vertex);
for (set<int>::const_iterator it = n.begin(); it != n.end(); ++it)
{
q.push(*it);
}
print_newline = true;
}
--curr_level;
if (curr_level == 0)
{
cout << (print_newline ? "\n" : "");
curr_level = q.size();
print_newline = false;
}
}
}
virtual void PrintDFS(const int _x) const
{
using namespace std;
if (m_list.find(_x) == m_list.end())
{
cout << _x << " not a vertex\n";
return;
}
stack<int> s;
set<int> visited;
s.push(_x);
while (!s.empty())
{
int vertex = s.top();
s.pop();
if (visited.find(vertex) == visited.end())
{
visited.insert(vertex);
cout << vertex << ", ";
set<int> n = Neighbours(vertex);
for (set<int>::const_iterator it = n.begin(); it != n.end(); ++it)
{
s.push(*it);
}
}
}
cout << "\n";
}
private:
std::map< int, std::set<int> > m_list;
std::map< int, T > m_val; // Use set instead of list because set is
// implemented as a bst -> better performance in
// search and use iterators to iterate
T m_default_value;
bool directed;
};
}
using namespace std;
template<typename T>
void list_neighbours(const Graph::AdjacencyList<T> & _adjlist, const int _vertex)
{
set<int> n = _adjlist.Neighbours(_vertex);
cout << _vertex << "->";
for (set<int>::const_iterator it = n.begin(); it != n.end(); ++it)
{
cout << *it << ", ";
}
cout << "\n";
}
int main(int argc, char **argv)
{
/**
* K(3,4) graph
*/
istringstream ss("1,4;1,5;1,6;1,7;2,4;2,5;2,6;2,7;3,4;3,5;3,6;3,7;");
const char default_val = ' ';
Graph::AdjacencyList<char> adjlist(ss, default_val);
assert(!adjlist.Adjacent(0, 10));
assert(!adjlist.Adjacent(1, 0));
assert(!adjlist.Adjacent(1, 1));
assert(!adjlist.Adjacent(1, 2));
assert(!adjlist.Adjacent(1, 3));
assert(adjlist.Adjacent(1, 4));
assert(adjlist.Adjacent(1, 5));
assert(adjlist.Adjacent(1, 6));
assert(adjlist.Adjacent(1, 7));
assert(!adjlist.Adjacent(1, 8));
assert(!adjlist.Adjacent(2, 0));
assert(!adjlist.Adjacent(2, 1));
assert(!adjlist.Adjacent(2, 2));
assert(!adjlist.Adjacent(2, 3));
assert(adjlist.Adjacent(2, 4));
assert(adjlist.Adjacent(2, 5));
assert(adjlist.Adjacent(2, 6));
assert(adjlist.Adjacent(2, 7));
assert(!adjlist.Adjacent(2, 8));
assert(!adjlist.Adjacent(3, 0));
assert(!adjlist.Adjacent(3, 1));
assert(!adjlist.Adjacent(3, 2));
assert(!adjlist.Adjacent(3, 3));
assert(adjlist.Adjacent(3, 4));
assert(adjlist.Adjacent(3, 5));
assert(adjlist.Adjacent(3, 6));
assert(adjlist.Adjacent(3, 7));
assert(!adjlist.Adjacent(3, 8));
assert(adjlist.Neighbours(1).size() == adjlist.Parents(1).size());
list_neighbours(adjlist, 1);
assert(adjlist.Neighbours(2).size() == adjlist.Parents(2).size());
list_neighbours(adjlist, 2);
assert(adjlist.Neighbours(3).size() == adjlist.Parents(3).size());
list_neighbours(adjlist, 3);
assert(adjlist.Neighbours(4).size() == adjlist.Parents(4).size());
list_neighbours(adjlist, 4);
assert(adjlist.Neighbours(5).size() == adjlist.Parents(5).size());
list_neighbours(adjlist, 5);
assert(adjlist.Neighbours(6).size() == adjlist.Parents(6).size());
list_neighbours(adjlist, 6);
assert(adjlist.Neighbours(7).size() == adjlist.Parents(7).size());
list_neighbours(adjlist, 7);
assert(adjlist.Neighbours(8).size() == 0);
assert(adjlist.Parents(8).size() == 0);
assert(adjlist.Add(2, 8));
assert(!adjlist.Add(8, 2));
assert(adjlist.Adjacent(2, 8));
assert(adjlist.Adjacent(8, 2));
assert(!adjlist.Adjacent(8, 3));
list_neighbours(adjlist, 2);
list_neighbours(adjlist, 8);
adjlist.Delete(2, 8);
list_neighbours(adjlist, 2);
list_neighbours(adjlist, 8);
assert(!adjlist.Adjacent(2, 8));
assert(!adjlist.Adjacent(8, 2));
assert(adjlist.GetValue(4) == ' ');
adjlist.SetValue(4, 'f');
assert(adjlist.GetValue(4) == 'f');
cout << "BFS: ";
adjlist.PrintBFS(6);
cout << "DFS: ";
adjlist.PrintDFS(6);
cout << "\n";
/**
* This graph:
* https://e...content-available-to-author-only...a.org/wiki/File:Directed_acyclic_graph.png
*/
istringstream ss2("7,11;7,8;5,11;3,8;3,10;11,2;11,9;11,10;8,9;");
Graph::AdjacencyList<char> adjlist2(ss2, default_val, true);
assert(adjlist2.Neighbours(7).size() == 2 && adjlist2.Parents(7).size() == 0);
assert(adjlist2.Neighbours(5).size() == 1 && adjlist2.Parents(5).size() == 0);
assert(adjlist2.Neighbours(3).size() == 2 && adjlist2.Parents(3).size() == 0);
assert(adjlist2.Neighbours(11).size() == 3 && adjlist2.Parents(11).size() == 2);
assert(adjlist2.Neighbours(8).size() == 1 && adjlist2.Parents(8).size() == 2);
assert(adjlist2.Neighbours(2).size() == 0 && adjlist2.Parents(2).size() == 1);
assert(adjlist2.Neighbours(9).size() == 0 && adjlist2.Parents(9).size() == 2);
assert(adjlist2.Neighbours(10).size() == 0 && adjlist2.Parents(10).size() == 2);
list_neighbours(adjlist2, 7);
list_neighbours(adjlist2, 5);
list_neighbours(adjlist2, 3);
list_neighbours(adjlist2, 11);
list_neighbours(adjlist2, 8);
list_neighbours(adjlist2, 2);
list_neighbours(adjlist2, 9);
list_neighbours(adjlist2, 10);
cout << "BFS: ";
adjlist2.PrintBFS(7);
cout << "DFS: ";
adjlist2.PrintDFS(7);
cout << "\n";
return 0;
}