u01: Add iterative print with cycle detection

This commit is contained in:
Simon Bruder 2023-04-22 13:36:45 +02:00
parent 1f56b00800
commit ffc4c3e6dd
3 changed files with 61 additions and 0 deletions

View file

@ -1,5 +1,6 @@
#include <iostream>
#include <sstream>
#include <stack>
#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<std::pair<const node *, size_t>> stack;
stack.push(std::make_pair(this, 0));
std::set<const node *> 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;

View file

@ -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<const node *> visited = {}) const;
std::string print_iterative() const;
private:
std::string name;

View file

@ -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;
}