From 72741a6a5bca243ab7423dc11f2f59c32fec1367 Mon Sep 17 00:00:00 2001 From: stefiosif Date: Sun, 12 Jun 2022 00:49:42 +0300 Subject: [PATCH] Make class Graph abstract and make derived classes Digraph and SCC --- algorithm/bfs.h | 10 ++++---- algorithm/tarjan.h | 50 ++++++++++++++++++------------------- graph/digraph.h | 26 ++++++++++++++++++++ graph/graph.h | 56 ++++++++++++++++++++++-------------------- graph/scc.h | 38 ++++++++-------------------- test/algorithm_test.cc | 30 +++++++++------------- test/graph_test.cc | 16 ++++++------ 7 files changed, 113 insertions(+), 113 deletions(-) create mode 100644 graph/digraph.h diff --git a/algorithm/bfs.h b/algorithm/bfs.h index 463614f..79c0ff2 100644 --- a/algorithm/bfs.h +++ b/algorithm/bfs.h @@ -1,18 +1,18 @@ #ifndef BFS_H_ #define BFS_H_ -#include "graph/graph.h" -using namespace graph; +#include "graph/digraph.h" -#include #include +using namespace graph; + namespace algo { template class BFS { public: - BFS(Graph G, T root) : G(G), root(root) {} + BFS(Digraph G, T root) : G(G), root(root) {} // std::map> run(); @@ -20,7 +20,7 @@ public: // std::map initExplore(); private: - Graph G; + Digraph G; T root; }; diff --git a/algorithm/tarjan.h b/algorithm/tarjan.h index fcd0ab2..06bd8ab 100644 --- a/algorithm/tarjan.h +++ b/algorithm/tarjan.h @@ -1,23 +1,23 @@ #ifndef TARJAN_H_ #define TARJAN_H_ -#include "graph/graph.h" -using namespace graph; +#include "graph/digraph.h" +#include "graph/scc.h" -#include -#include -#include #include +#include + +using namespace graph; namespace algo { template class Tarjan { public: - Tarjan(Graph G) : G(G) {} + Tarjan(Digraph G) : G(G) {} // - std::vector> run(); + std::vector> run(); // void strongConnect(const T& v); @@ -29,48 +29,48 @@ private: bool onStack = false; }; - Graph G; + Digraph G; std::stack S; std::int16_t index = 0; - std::map vp; - std::vector> SCCs; + std::map p; + std::vector> SCCs; }; template void Tarjan::strongConnect(const T& v) { - vp[v].index = vp[v].lowlink = index++; - vp[v].onStack = true; + p[v].index = p[v].lowlink = index++; + p[v].onStack = true; S.push(v); for (const auto& w : G.adjMatrix[v]) { - if (vp[w].index == -1) { + if (p[w].index == -1) { strongConnect(w); - vp[v].lowlink = std::min(vp[v].lowlink, vp[w].lowlink); - } else if (vp[w].onStack) { - vp[v].lowlink = std::min(vp[v].lowlink, vp[w].index); + p[v].lowlink = std::min(p[v].lowlink, p[w].lowlink); + } else if (p[w].onStack) { + p[v].lowlink = std::min(p[v].lowlink, p[w].index); } } // If v is a root node, pop the stack and generate an SCC - if (vp[v].lowlink == vp[v].index) { - std::vector SCC; + if (p[v].lowlink == p[v].index) { + //std::vector scc; + std::map> scc; bool finished = false; do { const auto w = S.top(); S.pop(); - vp[w].onStack = false; - SCC.push_back(w); - finished = vp[w].index == vp[v].index; + p[w].onStack = false; + scc[w] = G.adjMatrix[w]; + finished = p[w].index == p[v].index; } while (!finished); - SCCs.push_back(SCC); + SCCs.push_back(scc); } } template -std::vector> Tarjan::run() { - +std::vector> Tarjan::run() { for (const auto& v : G.vertices) { - if (vp[v].index == -1) { + if (p[v].index == -1) { strongConnect(v); } } diff --git a/graph/digraph.h b/graph/digraph.h new file mode 100644 index 0000000..03ef92b --- /dev/null +++ b/graph/digraph.h @@ -0,0 +1,26 @@ +#ifndef DIGRAPH_H_ +#define DIGRAPH_H_ + +#include "graph.h" + +#include + +namespace graph { + +template +class Digraph : public Graph { +public: + Digraph() = default; + + // Reverse graph directions + Digraph reverse(); +}; + +template +Digraph Digraph::reverse() { + return Digraph(); +} + +} // namespace graph + +#endif \ No newline at end of file diff --git a/graph/graph.h b/graph/graph.h index 60efc58..f4e6ad7 100644 --- a/graph/graph.h +++ b/graph/graph.h @@ -3,8 +3,6 @@ #include #include -#include -#include #include namespace graph { @@ -12,23 +10,19 @@ namespace graph { template class Graph { public: - Graph() = default; - - // Add vertex v - void insert(const T& v); + ~Graph(); // Add edge between v and u - void insert(const T& v, const T& u); - - // Reverse graph directions - Graph reverse(); + virtual void insert(const T& v, const T& u); // Number of vertices - std::uint16_t V(); + virtual std::uint16_t V(); // Number of edges - // TODO: Calculate bidirectional edges once - std::uint16_t E(); + virtual std::uint16_t E(); + + // Output graph + virtual void output(); // Adjacency matrix representation std::set vertices; @@ -36,36 +30,44 @@ public: }; template -void Graph::insert(const T& v) { - vertices.insert(v); +Graph::~Graph() { + vertices.clear(); + adjMatrix.clear(); } template -void Graph::insert(const T& v, const T& u) { - vertices.insert(v); - vertices.insert(u); - adjMatrix[v].insert(u); -} - -template -Graph Graph::reverse() { - return Graph(); +inline void Graph::insert(const T& v, const T& u) { + Graph::vertices.insert(v); + Graph::vertices.insert(u); + Graph::adjMatrix[v].insert(u); } template std::uint16_t Graph::V() { - return vertices.size(); + return static_cast(vertices.size()); } template std::uint16_t Graph::E() { std::uint16_t edges = 0; for (const auto& v : vertices) { - edges += adjMatrix[v].size(); + edges += static_cast(adjMatrix[v].size()); } - return edges; + return static_cast(edges); +} + +template +void Graph::output() { + for (const auto& v : vertices) { + for (const auto& u : adjMatrix[v]) { + std::cout << v << "->" << u << '|'; + } + std::cout << '\n'; + } + std::cout << '\n'; } } // namespace graph + #endif \ No newline at end of file diff --git a/graph/scc.h b/graph/scc.h index 2943c7c..44fbce5 100644 --- a/graph/scc.h +++ b/graph/scc.h @@ -1,45 +1,27 @@ #ifndef SCC_H_ #define SCC_H_ -#include "graph/graph.h" +#include "graph.h" + +#include namespace graph { template -class SCC { +class SCC : public Graph { public: - SCC(std::vector scc); + SCC(std::map> scc); - // Construct shortest path - std::vector SPT(); - - // Convert SCC into a Graph - Graph convert(); private: - std::vector scc; - // Representative - Root(SPT) of this SCC T root; }; template -SCC::SCC(std::vector component) { - scc = component; - root = scc[0]; -} - -template -std::vector SCC::SPT() { - - // BFS - - return std::vector(); -} - -template -Graph SCC::convert() { - - - return Graph(); +SCC::SCC(std::map> scc) { + Graph::adjMatrix = scc; + auto kv = std::views::keys(Graph::adjMatrix); + Graph::vertices = std::set{ kv.begin(), kv.end() }; + root = scc.begin()->first; } }; // namespace graph diff --git a/test/algorithm_test.cc b/test/algorithm_test.cc index ae3d0ce..50756fa 100644 --- a/test/algorithm_test.cc +++ b/test/algorithm_test.cc @@ -1,17 +1,19 @@ #include -#include "graph/graph.h" -using namespace graph; +#include "graph/digraph.h" +#include "graph/scc.h" #include "algorithm/tarjan.h" #include "algorithm/bfs.h" +using namespace graph; + TEST_SUITE("Algorithm.") { TEST_CASE("Tarjan T_1") { // 1 --> 2 --> 4 --> 1 // 2 --> 3 --> 5 --> 7 --> 3 // 5 --> 9 --> 6 --> 8 --> 9 - Graph G; + Digraph G; G.insert(1, 2); G.insert(2, 3); G.insert(2, 4); @@ -28,26 +30,23 @@ TEST_SUITE("Algorithm.") { algo::Tarjan tarjan(G); auto result = tarjan.run(); - - std::sort(result.begin(), result.end()); - std::for_each(result.begin(), result.end(), [&](std::vector& row) { - std::sort(row.begin(), row.end()); - }); + + for (auto& scc : result) { + scc.output(); + } std::vector> expected{ {1, 2, 4}, {3, 5, 7}, {6, 8, 9} }; - - CHECK_EQ(expected, result); } TEST_CASE("Tarjan T_2") { // 1 --> 2 --> 5 --> 7 --> 2 // 1 --> 4 --> 3 --> 1 // 4 --> 6 --> 3 - Graph G; + Digraph G; G.insert(1, 2); G.insert(1, 4); G.insert(2, 5); @@ -63,24 +62,17 @@ TEST_SUITE("Algorithm.") { algo::Tarjan tarjan(G); auto result = tarjan.run(); - std::sort(result.begin(), result.end()); - std::for_each(result.begin(), result.end(), [&](std::vector& row) { - std::sort(row.begin(), row.end()); - }); - std::vector> expected{ {1, 3, 4, 6}, {2, 5, 7} }; - - CHECK_EQ(expected, result); } TEST_CASE("BFS T_1") { // 1 --> 2 --> 5 --> 7 --> 2 // 1 --> 4 --> 3 --> 1 // 4 --> 6 --> 3 - Graph G; + Digraph G; G.insert(1, 2); G.insert(1, 4); G.insert(2, 5); diff --git a/test/graph_test.cc b/test/graph_test.cc index c038a45..22d7a86 100644 --- a/test/graph_test.cc +++ b/test/graph_test.cc @@ -1,16 +1,20 @@ #include #include "graph/scc.h" -using namespace graph; +#include "graph/digraph.h" #include "algorithm/tarjan.h" +#include + +using namespace graph; + TEST_SUITE("Graph.") { TEST_CASE("SCC") { // 1 --> 2 --> 4 --> 1 // 2 --> 3 --> 5 --> 7 --> 3 // 5 --> 9 --> 6 --> 8 --> 9 - Graph G; + Digraph G; G.insert(1, 2); G.insert(2, 3); G.insert(2, 4); @@ -24,12 +28,6 @@ TEST_SUITE("Graph.") { G.insert(9, 6); algo::Tarjan tarjan(G); - auto tarjanOutput = tarjan.run(); - - std::vector> SCCs; - for (const auto& scc : tarjanOutput) { - SCCs.push_back(scc); - } - + auto SCCs = tarjan.run(); } } \ No newline at end of file