u01: Add iterative print with cycle detection
This commit is contained in:
parent
1f56b00800
commit
ffc4c3e6dd
31
u01/node.cpp
31
u01/node.cpp
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Reference in a new issue