Add iteration and unique check
This commit is contained in:
parent
f61fe57a40
commit
f2a8d58b24
3 changed files with 113 additions and 32 deletions
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
Node* root = new Node("root");
|
Node* root = new Node("root");
|
||||||
Node* left_child = new Node("left child");
|
Node* left_child = new Node("left child");
|
||||||
|
@ -14,11 +15,26 @@ int main() {
|
||||||
delete root;
|
delete root;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Node* auto_root = Node::create_complete_tree(2, 4);
|
/*
|
||||||
|
Node *auto_root = Node::create_complete_tree(2, 4);
|
||||||
|
|
||||||
std::cout << auto_root << std::endl;
|
std::cout << auto_root << std::endl;
|
||||||
|
|
||||||
delete auto_root;
|
delete auto_root;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// cycle test
|
||||||
|
Node *root = new Node;
|
||||||
|
Node *child1 = new Node;
|
||||||
|
Node *child2 = new Node;
|
||||||
|
|
||||||
|
root->add_child(child1);
|
||||||
|
root->add_child(child2);
|
||||||
|
|
||||||
|
// add cycle
|
||||||
|
child1->add_child(root);
|
||||||
|
|
||||||
|
std::cout << root << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
uint32_t Node::node_id = 0;
|
uint32_t Node::node_id = 0;
|
||||||
|
|
||||||
Node::Node(const std::string& name)
|
Node::Node(const std::string &name)
|
||||||
{
|
{
|
||||||
node_id++;
|
node_id++;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ Node::~Node()
|
||||||
{
|
{
|
||||||
std::cout << "enter ~node() of \"" << name << "\"" << std::endl;
|
std::cout << "enter ~node() of \"" << name << "\"" << std::endl;
|
||||||
|
|
||||||
for (Node* child : children)
|
for (Node *child : children)
|
||||||
{
|
{
|
||||||
delete child;
|
delete child;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ std::string Node::get_name() const
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::set_name(const std::string& new_name)
|
void Node::set_name(const std::string &new_name)
|
||||||
{
|
{
|
||||||
name = new_name;
|
name = new_name;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ int Node::get_nr_children() const
|
||||||
return children.size();
|
return children.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* Node::get_child(int i) const
|
Node *Node::get_child(int i) const
|
||||||
{
|
{
|
||||||
if (i < 0 || i >= static_cast<int>(children.size()))
|
if (i < 0 || i >= static_cast<int>(children.size()))
|
||||||
{
|
{
|
||||||
|
@ -57,15 +57,14 @@ Node* Node::get_child(int i) const
|
||||||
return children[i];
|
return children[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::add_child(Node* child)
|
void Node::add_child(Node *child)
|
||||||
{
|
{
|
||||||
children.emplace_back(child);
|
children.emplace_back(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::print(std::ostream& str, uint32_t depth) const
|
void Node::print(std::ostream &str, uint32_t depth) const
|
||||||
{
|
{
|
||||||
auto predicate = [&str](const Node* node, uint32_t depth)
|
auto predicate = [&str](const Node *node, uint32_t depth) {
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < depth; i++)
|
for (uint32_t i = 0; i < depth; i++)
|
||||||
{
|
{
|
||||||
str << "\t";
|
str << "\t";
|
||||||
|
@ -74,21 +73,21 @@ void Node::print(std::ostream& str, uint32_t depth) const
|
||||||
str << node->get_name() + "\n";
|
str << node->get_name() + "\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
Node::traverse_tree(this, predicate);
|
Node::traverse_tree(this, predicate, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* Node::create_complete_tree(uint32_t nr_child_nodes, uint32_t tree_depth)
|
Node *Node::create_complete_tree(uint32_t nr_child_nodes, uint32_t tree_depth)
|
||||||
{
|
{
|
||||||
if (tree_depth == 0)
|
if (tree_depth == 0)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* node = new Node;
|
Node *node = new Node;
|
||||||
|
|
||||||
for (uint32_t j = 0; j < nr_child_nodes; j++)
|
for (uint32_t j = 0; j < nr_child_nodes; j++)
|
||||||
{
|
{
|
||||||
Node* child = Node::create_complete_tree(nr_child_nodes, tree_depth - 1);
|
Node *child = Node::create_complete_tree(nr_child_nodes, tree_depth - 1);
|
||||||
|
|
||||||
if (child == nullptr)
|
if (child == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -101,17 +100,78 @@ Node* Node::create_complete_tree(uint32_t nr_child_nodes, uint32_t tree_depth)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::traverse_tree(const Node* node, std::function<void(const Node*, uint32_t)> predicate, uint32_t depth)
|
void Node::traverse_tree(const Node *node, std::function<void(const Node *, uint32_t)> predicate, bool recursive, uint32_t depth)
|
||||||
{
|
{
|
||||||
predicate(node, depth);
|
if (recursive)
|
||||||
|
|
||||||
for (Node* child : node->children)
|
|
||||||
{
|
{
|
||||||
Node::traverse_tree(child, predicate, depth + 1);
|
std::set<const Node *> visited;
|
||||||
|
traverse_tree_recursive(node, predicate, visited, depth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
traverse_tree_iterative(node, predicate, depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &os, const Node *node)
|
void Node::traverse_tree_recursive(const Node *node, std::function<void(const Node *, uint32_t)> predicate, std::set<const Node *> &visited, uint32_t depth)
|
||||||
|
{
|
||||||
|
if (visited.find(node) != visited.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate(node, depth);
|
||||||
|
|
||||||
|
visited.insert(node);
|
||||||
|
|
||||||
|
for (Node *child : node->children)
|
||||||
|
{
|
||||||
|
Node::traverse_tree_recursive(child, predicate, visited, depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::traverse_tree_iterative(const Node *node, std::function<void(const Node *, uint32_t)> predicate, uint32_t depth)
|
||||||
|
{
|
||||||
|
struct NodeInfo
|
||||||
|
{
|
||||||
|
const Node *node;
|
||||||
|
uint32_t depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::set<const Node *> visited;
|
||||||
|
std::vector<NodeInfo> stack;
|
||||||
|
|
||||||
|
NodeInfo info = {.node = node, .depth = 0};
|
||||||
|
stack.emplace_back(info);
|
||||||
|
|
||||||
|
while (!stack.empty())
|
||||||
|
{
|
||||||
|
// get the last node and remove it from the stack
|
||||||
|
NodeInfo current = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
// check if we already visited this node
|
||||||
|
if (visited.find(current.node) != visited.end())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute given function
|
||||||
|
predicate(current.node, current.depth);
|
||||||
|
|
||||||
|
// mark this node as visited
|
||||||
|
visited.insert(current.node);
|
||||||
|
|
||||||
|
// push children to the stack
|
||||||
|
for (auto child = current.node->children.rbegin(); child != current.node->children.rend(); child++)
|
||||||
|
{
|
||||||
|
NodeInfo info = {.node = *child, .depth = current.depth + 1};
|
||||||
|
stack.emplace_back(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &os, const Node *node)
|
||||||
{
|
{
|
||||||
node->print(os);
|
node->print(os);
|
||||||
|
|
||||||
|
|
|
@ -6,31 +6,36 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
class Node {
|
class Node
|
||||||
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Node(const std::string& name = "");
|
Node(const std::string &name = "");
|
||||||
virtual ~Node();
|
virtual ~Node();
|
||||||
|
|
||||||
std::string get_name() const;
|
std::string get_name() const;
|
||||||
void set_name(const std::string& new_name);
|
void set_name(const std::string &new_name);
|
||||||
|
|
||||||
int get_nr_children() const;
|
int get_nr_children() const;
|
||||||
Node* get_child(int i) const;
|
Node *get_child(int i) const;
|
||||||
void add_child(Node* child);
|
void add_child(Node *child);
|
||||||
|
|
||||||
void print(std::ostream& str = std::cout, uint32_t depth = 0) const;
|
void print(std::ostream &str = std::cout, uint32_t depth = 0) const;
|
||||||
static Node* create_complete_tree(uint32_t nr_child_nodes, uint32_t tree_depth);
|
static Node *create_complete_tree(uint32_t nr_child_nodes, uint32_t tree_depth);
|
||||||
static void traverse_tree(const Node* node, std::function<void(const Node*, uint32_t)> predicate, uint32_t depth = 0);
|
static void traverse_tree(const Node *node, std::function<void(const Node *, uint32_t)> predicate, bool recursive, uint32_t depth = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<Node*> children;
|
std::vector<Node *> children;
|
||||||
|
|
||||||
static uint32_t node_id;
|
static uint32_t node_id;
|
||||||
|
|
||||||
|
static void traverse_tree_recursive(const Node *node, std::function<void(const Node *, uint32_t)> predicate, std::set<const Node *> &visited, uint32_t depth = 0);
|
||||||
|
static void traverse_tree_iterative(const Node *node, std::function<void(const Node *, uint32_t)> predicate, uint32_t depth = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::ostream& operator<<(std::ostream &os, const Node *node);
|
extern std::ostream &operator<<(std::ostream &os, const Node *node);
|
||||||
|
|
||||||
#endif // NODE_H
|
#endif // NODE_H
|
Loading…
Reference in a new issue