Simon Bruder
db4d489ae8
size_t should only be used for indexing. For all other purposes, unsigned int should be used.
110 lines
3.1 KiB
C++
110 lines
3.1 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <stack>
|
|
|
|
#include "node.h"
|
|
|
|
unsigned int node::node_id = 0;
|
|
|
|
node::node(const std::string &name) : name(name) {
|
|
node_id++;
|
|
if (name.empty()) {
|
|
std::stringstream node_sm;
|
|
node_sm << "node_" << node_id;
|
|
this->name = node_sm.str();
|
|
}
|
|
}
|
|
|
|
node::~node() {
|
|
std::cout << "enter ~node() of \"" << get_name() << "\"" << std::endl;
|
|
this->destroy = true;
|
|
for (node *child : children) {
|
|
if (!child->destroy) {
|
|
delete child;
|
|
}
|
|
}
|
|
std::cout << "leave ~node() of \"" << get_name() << "\"" << std::endl;
|
|
}
|
|
|
|
std::string node::get_name() const { return name; }
|
|
|
|
void node::set_name(const std::string new_name) { this->name = new_name; }
|
|
|
|
std::size_t node::get_nr_children() const { return children.size(); }
|
|
|
|
node *node::get_child(std::size_t i) const { return children[i]; }
|
|
|
|
void node::add_child(node *child) { children.push_back(child); }
|
|
|
|
void node::print(std::ostream &str, unsigned int depth) const {
|
|
str << std::string(depth, '\t') << get_name() << std::endl;
|
|
for (node *child : children) {
|
|
child->print(str, depth + 1);
|
|
}
|
|
}
|
|
|
|
std::string node::print_recursive(unsigned int depth,
|
|
std::set<const node *> visited) const {
|
|
std::stringstream output;
|
|
output << std::string(depth, '\t') << get_name();
|
|
visited.insert(this);
|
|
for (const node *child : children) {
|
|
// std::set::contains is only implemented in C++20
|
|
if (visited.find(child) == visited.end()) {
|
|
output << std::endl << child->print_recursive(depth + 1, visited);
|
|
} else {
|
|
output << " [↝ " << child->get_name() << "]";
|
|
}
|
|
}
|
|
if (depth == 0)
|
|
output << std::endl;
|
|
return output.str();
|
|
}
|
|
|
|
std::string node::print_iterative() const {
|
|
std::stringstream output;
|
|
std::stack<std::pair<const node *, unsigned int>> stack;
|
|
stack.push(std::make_pair(this, 0));
|
|
std::set<const node *> visited = {};
|
|
|
|
while (!stack.empty()) {
|
|
const node *n = nullptr;
|
|
unsigned int 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 (unsigned int 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;
|
|
}
|
|
|
|
node *create_complete_tree(std::size_t nr_child_nodes,
|
|
unsigned int tree_depth) {
|
|
node *n = new node();
|
|
if (tree_depth > 1) {
|
|
for (std::size_t i = 0; i < nr_child_nodes; i++) {
|
|
n->add_child(create_complete_tree(nr_child_nodes, tree_depth - 1));
|
|
}
|
|
}
|
|
return n;
|
|
}
|