Skip to content

Instantly share code, notes, and snippets.

@cleoold
Created May 30, 2020 03:46
Show Gist options
  • Save cleoold/3f9d186a1cad7d79dea8ba631fce0eb3 to your computer and use it in GitHub Desktop.
Save cleoold/3f9d186a1cad7d79dea8ba631fce0eb3 to your computer and use it in GitHub Desktop.
tree implementation with strict ownership
#include <functional>
#include <iostream>
#include <memory>
#include <queue>
#include <vector>
template<typename V>
class Tree;
template<typename V>
using UTree = std::unique_ptr<Tree<V>>;
template<typename V>
using VecUTree = std::vector<UTree<V>>;
template<typename V>
class Tree {
private:
V _value;
const std::unique_ptr<VecUTree<V>> children = std::make_unique<VecUTree<V>>();
public:
using value_type = V;
using callback_type = std::function<void(Tree&)>;
Tree(V value)
:_value(value)
{}
Tree(Tree&&) = delete;
V &value() {
return _value;
}
bool isleaf() {
return children->empty();
}
Tree &add_child(UTree<V> t) {
children->emplace_back(std::move(t));
return *this;
}
Tree &add_child(V v) {
children->emplace_back(std::make_unique<Tree>(v));
return *this;
}
Tree &child_at(size_t i) {
return *(children->at(i));
}
UTree<V> move_child(size_t i) {
auto t = std::move(children->at(i));
children->erase(children->begin() + i);
return t;
}
Tree &visit(callback_type f) {
f(*this);
return *this;
}
void level_traverse(callback_type f) {
std::queue<Tree *> que;
que.emplace(this);
while (!que.empty()) {
Tree *node = que.front();
que.pop();
node->visit(f);
for (auto &&n : *(node->children))
que.push(&(*n));
}
}
void preorder_traverse(callback_type f) {
std::vector<Tree *> stk;
stk.push_back(this);
while (!stk.empty()) {
Tree *node = stk.back();
stk.pop_back();
node->visit(f);
for (auto it = node->children->rbegin(); it < node->children->rend(); ++it)
stk.emplace_back(&(**it));
}
}
void postorder_traverse(callback_type f) {
using RecordT = std::pair<Tree *, bool>;
std::vector<RecordT> records;
records.push_back({this, false});
while (!records.empty()) {
RecordT &record = records.back();
Tree *node = record.first;
if (record.second) {
records.pop_back();
node->visit(f);
continue;
}
record.second = true;
for (auto it = node->children->rbegin(); it < node->children->rend(); ++it)
records.emplace_back(RecordT{&(**it), false});
}
}
void inorder_traverse(callback_type) = delete;
};
int main() {
using IntTree = Tree<int>;
IntTree t(1);
t.add_child(2).add_child(3).add_child(4);
t.child_at(0).add_child(3).add_child(33);
t.child_at(1).add_child(4);
t.child_at(1).child_at(0).add_child(33);
const auto pt = [](auto &x){ std::cout << x.value() << ", "; };
std::cout << "level order:" << std::endl;
t.level_traverse(pt);
std::cout << std::endl;
std::cout << "preorder:" << std::endl;
t.preorder_traverse(pt);
std::cout << std::endl;
std::cout << "postorder:" << std::endl;
t.postorder_traverse(pt);
std::cout << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment