#include <iostream>
#include <list>
#include <queue>
#include <stack>
using namespace std;
template<typename VT, typename Einfo = double>
class AGraph {
struct Edge_Node {
unsigned int v;
Einfo edge_info; // example weight
Edge_Node* next{ 0 };
Edge_Node() = default;
Edge_Node(unsigned int v, Einfo edge_info) :v(v),edge_info(edge_info), next(0) {}
};
struct Vertex_Node {
VT vertex; // node data
Edge_Node* first_edge_node{ 0 };
Vertex_Node() = default;
Vertex_Node(VT v) :vertex(v) {}
};
vector<Vertex_Node> vertices;
vector<bool> marks;
unsigned int en{ 0 };
bool undirected{ true };
public:
AGraph(bool undirected = true) :undirected(undirected) {}; // empty graph
void add_vertex(const VT& v) { this->vertices.push_back(Vertex_Node(v)); }
VT operator[](int i) const { return this->vertices[i].vertex; }
VT &operator[](int i) { return this->vertices[i].vertex; }
bool add_edge(unsigned int v1, unsigned int v2, Einfo edgeInfo)
{
Edge_Node* p = new Edge_Node(v2, edgeInfo);
if (!p) return false;
p->next = this->vertices[v1].first_edge_node;
this->vertices[v1].first_edge_node = p;
if (this->undirected)
{
p = new Edge_Node(v1, edgeInfo);
if (!p) return false;
p->next = this->vertices[v2].first_edge_node;
this->vertices[v2].first_edge_node = p;
}
return true;
}
void set_edge(const int i, const int j, const Einfo &info)
{
Edge_Node *p = this->vertices[i].first_edge_node;
while (p)
{
if (p->v == j) p->edge_info = info;
p = p->next;
}
if (this->undirected)
{
p = this->vertices[j].first_edge_node;
while (p)
{
if (p->v == i) p->edge_info = info;
p = p->next;
}
}
}
void print_adjList()
{
for (auto &vnode : this->vertices)
{
std::cout << vnode.vertex << ":";
Edge_Node *p = vnode.first_edge_node;
while (p)
{
std::cout << p->v << ", " << p->edge_info << " ";
p = p->next;
}
std::cout << std::endl;
}
}
void print()
{
std::cout << "node info: \n";
for (auto &v : this->vertices)
{
std::cout << v.vertex << "\n";
}
std::cout << "adjust sheet: \n";
print_adjList();
}
void clear_marks()
{
if (this->marks.size() != this->vertices.size())
{
this->marks.resize(this->vertices.size(), false);
}
for (unsigned int i = 0; i < this->marks.size(); i++)
{
this->marks[i] = false;
}
}
void DFS(unsigned int v, void(*visit_vertex)(const VT &vertex))
{
if (v < 0 || v >= vertices.size()) return;
this->marks[v] = true;
visit_vertex(this->vertices[v].vertex);
Edge_Node *p = this->vertices[v].first_edge_node;
while (p)
{
auto w = p->v;
if (this->marks[w] == false)
{
DFS(w, visit_vertex);
}
p = p->next;
}
}
void DFS(void(*visit_vertex)(const VT &vertex))
{
clear_marks();
for (int v = 0; v != this->vertices.size(); v++)
{
if (!this->marks[v])
{
DFS_(v, visit_vertex);
}
}
}
void DFS_(unsigned int v, void(*visit_vertex)(const VT &vertex))
{
if (v < 0 || v >= this->vertices.size()) return;
stack<int> S;
S.push(v);
this->marks[v] = true;
while (!S.empty)
{
auto v = S.top(); S.pop();
visit_vertex(this->vertices[v].vertex);
Edge_Node *p = this->vertices[v].first_edge_node;
while (p)
{
auto w = p->v;
if (this->marks[w] == false)
{
S.push(w);
this->marks[w] = true;
}
p = p->next;
}
}
}
void BFS(unsigned int v, void(*visit_vertex)(const VT &vertex))
{
if (v < 0 || v >= this->vertices.size()) return;
this->marks[v] = true;
queue<unsigned int> que;
que.push(v);
while (!que.empty())
{
auto v = que.front();
que.pop();
visit_vertex(this->vertices[v].vertex);
Edge_Node *p = this->vertices[v].first_edge_node;
while (p)
{
auto w = p->v;
if (this->marks[w] = false)
{
this->marks[w] = true;
que.push(w);
}
p = p->next;
}
}
}
void BFS(void(*visit_vertex)(const VT &vertex))
{
clear_marks();
for (int v = 0; v != this->vertices.size(); v++)
{
if (!this->marks[v])
{
BFS(v, visit_vertex);
}
}
}
};
inline void visit(const char &vertex)
{
std::cout << vertex << " ";
}
int main(int argc, char *argv[])
{
AGraph<char, double> G(false);
G.add_vertex('A');
G.add_vertex('B');
G.add_vertex('C');
G.add_vertex('D');
G.clear_marks();
G.add_edge(0, 1, 6.5);
G.add_edge(0, 2, 9.3);
G.add_edge(2, 3, 1.4);
G.add_edge(3, 0, 3.7);
G.print();
std::cout << std::endl;
return 0;
}