diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp new file mode 100644 index 0000000..288501c --- /dev/null +++ b/lib/src/graph.hpp @@ -0,0 +1,133 @@ +#ifndef __GRAPH_H__ +#define __GRAPH_H__ + +#include +#include +#include +#include +#include + +template +class Node { + public: + Node(NameType name) : name{name}, paths{} {} + NameType name{NameType()}; + std::unordered_map paths; + + void descr_path(Node* n, T lenght = 1) { paths[n] = lenght; } + + ~Node() { + paths = {}; + name = NameType(); + } +}; + +template +class Graph { + static_assert(std::is_arithmetic::value, + "Graph: paths' lenghts must be arithmetic!"); + + public: + Graph(std::initializer_list> links, + T base_lenght = 1) { + add_paths(links, base_lenght); + } + + Graph(std::initializer_list, T>> + links) { + add_paths(links); + } + + Node* find_via_name(NameType name) { + auto ans = std::find_if( + nodes.begin(), nodes.end(), + [&name](const Node* x) { return x->name == name; }); + if (ans == nodes.end()) { + return nullptr; + } + return *ans; + } + + Node* operator[](NameType name) { find_via_name(name); } + + void add_paths(std::initializer_list> links, + T base_lenght = 1) { + /* { {Name1, Name2}, ... }*/ + for (auto i : links) { + Node* first = find_via_name(i.first); + if (!first) { + first = new Node{i.first}; + nodes.push_back(first); + } + Node* second = find_via_name(i.second); + if (!second && first != second) { + second = new Node{i.second}; + nodes.push_back(second); + } + first->descr_path(second, base_lenght); + continue; + } + } + + void add_paths( + std::initializer_list, T>> + links) { + /* { { Name1, Name2 }, lenght }, ... } + */ + for (auto i : links) { + Node* first = find_via_name(i.first.first); + if (!first) { + first = new Node{i.first.first}; + nodes.push_back(first); + } + Node* second = find_via_name(i.first.second); + if (!second && first != second) { + second = new Node{i.first.second}; + nodes.push_back(second); + } + first->descr_path(second, i.second); + continue; + } + } + + ~Graph() { + for (Node* i : nodes) { + delete i; + } + nodes = {}; + } + + void see_vertical() { + for (auto i : nodes) { + if (i->paths.size() == 0) { + std::cout << i->name << std::endl; + continue; + } + for (auto k : i->paths) { + std::cout << i->name << " -> " << k.first->name << ", l:" << k.second + << std::endl; + } + } + } + + friend std::ostream& operator<<(std::ostream& os, + const Graph& g) { + os << "Graph( "; + for (auto i : g.nodes) { + if (i->paths.size() == 0) { + os << "{" << i->name << "}"; + continue; + } + for (auto k : i->paths) { + os << "{" << i->name << " -> " << k.first->name << ", l:" << k.second + << "}, "; + } + } + os << ")"; + return os; + } + + std::vector*> nodes; +}; + +#endif diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 76e8197..c3aeba4 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -1 +1 @@ -int main() { return 0; } +int main() { return 0; } \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..4f86f1a 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,73 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] -} \ No newline at end of file +#include + +#include "topological_sort.hpp" + +template +bool check_graph_sorted(Graph& g) { + for (auto i : g.nodes) { + for (auto k : i->paths) { + if (i->name >= k.first->name) { + return false; + } + } + } + return true; +} + +TEST(TopologySort, TestSimple1) { + Graph g({{1, 4}, {4, 2}, {3, 2}, {4, 3}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestSimple2) { + Graph g({{1, 2}, {3, 2}, {2, 5}, {4, 2}, {4, 6}, {6, 5}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestExtraSourcePoint1) { + Graph g({{1, 2}, {3, 2}, {2, 5}, {4, 2}, {4, 6}, {6, 5}, {8, 6}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestExtraSourcePoint2) { + Graph g({{1, 2}, {3, 2}, {8, 5}, {2, 5}, {4, 2}, {4, 6}, {6, 5}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestExtraSourcePoint3) { + Graph g({{1, 4}, {4, 2}, {3, 2}, {4, 3}, {9, 1}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestExtraSourcePoint4) { + Graph g({{1, 2}, {3, 2}, {6, 5}, {2, 5}, {4, 2}, {4, 6}, {6, 5}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestExtraLeafPoint) { + Graph g({{1, 2}, {3, 2}, {6, 9}, {2, 5}, {4, 2}, {4, 6}, {6, 5}}); + ASSERT_EQ(check_graph_sorted(topological_sort(g)), true); // Stack [] +} + +TEST(TopologySort, TestLoopError1) { + Graph g({{1, 4}, {4, 2}, {3, 2}, {4, 3}, {3, 3}}); + EXPECT_THROW(topological_sort(g), std::runtime_error); // Stack [] +} + +TEST(TopologySort, TestLoopError2) { + Graph g({{1, 2}, {1, 3}, {3, 2}, {2, 3}}); + EXPECT_THROW(topological_sort(g), std::runtime_error); // Stack [] +} + +TEST(TopologySort, TestLoopError3) { + Graph g({{1, 4}, {4, 2}, {3, 2}, {4, 3}, {4, 1}}); + EXPECT_THROW(topological_sort(g), + std::runtime_error); // Stack [] +} + +TEST(TopologySort, TestLoopError4) { + Graph g({{1, 2}, {1, 3}, {3, 2}, {2, 3}, {2, 1}, {3, 1}}); + EXPECT_THROW(topological_sort(g), std::runtime_error); // Stack [] +} diff --git a/task_01/src/topological_sort.hpp b/task_01/src/topological_sort.hpp new file mode 100644 index 0000000..89698df --- /dev/null +++ b/task_01/src/topological_sort.hpp @@ -0,0 +1,49 @@ +#ifndef __TOPOLOG_SORT_H__ +#define __TOPOLOG_SORT_H__ + +#include +#include + +#include "../../lib/src/graph.hpp" + +template +void topological_rec(std::vector*>& st, Node* n) { + if (n->name == 0) { + n->name = 1; + // 1 - adjacent (as leafs) points + + for (auto i : n->paths) { + topological_rec(st, i.first); + } + n->name = 2; + st.push_back(n); + + } else if (n->name == 2) { + return; + } else { + throw std::runtime_error("Incorrect graph"); + } +} + +template +Graph& topological_sort(Graph& g) { + std::vector*> marked_points; + for (auto i : g.nodes) { + i->name = 0; + // 0 - clear points + } + + // point_stack.push(g.nodes[0]); + for (auto i : g.nodes) { + if (i->name == 0) { + topological_rec(marked_points, i); + } + } + int stack_size = marked_points.size(); + for (int i = 1; i < stack_size + 1; ++i) { + marked_points[stack_size - i]->name = i; + } + return g; +} + +#endif \ No newline at end of file