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 <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
|
@ -60,6 +61,36 @@ std::string node::print_recursive(std::size_t depth,
|
||||||
return output.str();
|
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) {
|
std::ostream &operator<<(std::ostream &os, node &n) {
|
||||||
n.print(os);
|
n.print(os);
|
||||||
return os;
|
return os;
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
void print(std::ostream &str, std::size_t depth = 0) const;
|
void print(std::ostream &str, std::size_t depth = 0) const;
|
||||||
std::string print_recursive(std::size_t depth = 0,
|
std::string print_recursive(std::size_t depth = 0,
|
||||||
std::set<const node *> visited = {}) const;
|
std::set<const node *> visited = {}) const;
|
||||||
|
std::string print_iterative() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -163,3 +163,32 @@ TEST_CASE("Cycle detection") {
|
||||||
|
|
||||||
delete n;
|
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