From ffc4c3e6dd15d58c41db2d32a04cf7ccf02802e0 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Sat, 22 Apr 2023 13:36:45 +0200 Subject: [PATCH] u01: Add iterative print with cycle detection --- u01/node.cpp | 31 +++++++++++++++++++++++++++++++ u01/node.h | 1 + u01/tests.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/u01/node.cpp b/u01/node.cpp index 347dd78..4658534 100644 --- a/u01/node.cpp +++ b/u01/node.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "node.h" @@ -60,6 +61,36 @@ std::string node::print_recursive(std::size_t depth, return output.str(); } +std::string node::print_iterative() const { + std::stringstream output; + std::stack> stack; + stack.push(std::make_pair(this, 0)); + std::set visited = {}; + + while (!stack.empty()) { + const node *n = nullptr; + size_t depth; + std::tie(n, depth) = stack.top(); + stack.pop(); + if (visited.find(n) == visited.end()) { + if (n != this) + output << std::endl; + output << std::string(depth, '\t') << n->get_name(); + // Complex iteration (not default vector iteration is necessary, + // to achieve the same output as the recursive approach. + // Otherwise, the order of the children is reversed (due to LIFO). + for (size_t i = n->get_nr_children(); i > 0; i--) { + stack.push(std::make_pair(n->get_child(i - 1), depth + 1)); + } + } else { + output << " [↝ " << n->get_name() << "]"; + } + visited.insert(n); + } + output << std::endl; + return output.str(); +} + std::ostream &operator<<(std::ostream &os, node &n) { n.print(os); return os; diff --git a/u01/node.h b/u01/node.h index b30131e..a8d5edc 100644 --- a/u01/node.h +++ b/u01/node.h @@ -17,6 +17,7 @@ public: void print(std::ostream &str, std::size_t depth = 0) const; std::string print_recursive(std::size_t depth = 0, std::set visited = {}) const; + std::string print_iterative() const; private: std::string name; diff --git a/u01/tests.cpp b/u01/tests.cpp index add4715..a2000f5 100644 --- a/u01/tests.cpp +++ b/u01/tests.cpp @@ -163,3 +163,32 @@ TEST_CASE("Cycle detection") { delete n; } + +TEST_CASE("Cycle detection (iterative)") { + node *n = new node("foo"); + n->add_child(new node("bar")); + n->get_child(0)->add_child(n); + + std::stringstream output; + output << n->print_iterative(); + + REQUIRE(output.str() == "foo\n\tbar [↝ foo]\n"); + + delete n; +} + +TEST_CASE("Equivalence of interative and recursive print") { + node *n = new node(); + REQUIRE(n->print_recursive() == n->print_iterative()); + delete n; + + node *r = new node("foo"); + r->add_child(new node("bar")); + r->get_child(0)->add_child(r); + REQUIRE(r->print_recursive() == r->print_iterative()); + delete r; + + node *t = create_complete_tree(2, 4); + REQUIRE(t->print_recursive() == t->print_iterative()); + delete t; +}