Created
May 30, 2020 03:46
-
-
Save cleoold/3f9d186a1cad7d79dea8ba631fce0eb3 to your computer and use it in GitHub Desktop.
tree implementation with strict ownership
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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