19#ifndef OPEN_CPP_UTILS_DIRECTED_TREE_H
20#define OPEN_CPP_UTILS_DIRECTED_TREE_H
27namespace open_cpp_utils
37template<
typename T,
class Alloc = std::allocator<T>>
58 using node_queue = std::deque<node>;
61 using s_alloc = Alloc;
62 using h_alloc =
typename std::allocator_traits<s_alloc>::template rebind_alloc<Node_>;
63 using hierarchy = Node_*;
64 using storage = data_type*;
70 static constexpr std::integral_constant<node, 0> root{};
83 node parent, child, prev_sibling, next_sibling;
84 uint32_t flags, depth;
86 Node_() : parent(0), child(0), prev_sibling(0), next_sibling(0), flags(0), depth(0) { }
98 hierarchy g_old = graph_;
99 storage d_old = data_;
100 size_t c_old = capacity_;
102 if(capacity_ == 0) capacity_ = 10;
105 graph_ = g_alloc_.allocate(capacity_);
106 data_ = d_alloc_.allocate(capacity_);
110 std::memcpy(graph_, g_old, size_ *
sizeof(Node_));
111 std::memcpy(data_, d_old, size_ *
sizeof(data_type));
113 for(node i = size_; i < capacity_; ++i)
116 std::construct_at(data_ + i);
121 for(node i = 0; i < capacity_; ++i)
124 std::construct_at(data_ + i);
127 graph_[0].flags = Node_::valid;
130 g_alloc_.deallocate(g_old, c_old);
131 d_alloc_.deallocate(d_old, c_old);
134 node push_back_(
const data_type& data)
136 if(size_ >= capacity_) grow_();
137 std::construct_at(data_ + size_, data);
141 node push_back_(data_type&& data)
143 if(size_ >= capacity_) grow_();
144 std::construct_at(data_ + size_, std::forward<T>(data));
157 : size_(0), capacity_(0)
158 , graph_(nullptr), data_(nullptr)
162 : size_(0), capacity_(0)
163 , graph_(nullptr), data_(nullptr)
164 { push_back_(std::forward<T>(data)); }
167 : size_(0), capacity_(0)
168 , graph_(nullptr), data_(nullptr)
169 { push_back_(data); }
171 ~directed_tree() =
default;
181 [[nodiscard]]
bool valid(node
id)
const {
return graph_ ? graph_[id].flags & Node_::valid :
false; }
188 [[nodiscard]] node
parent(node
id)
const {
return graph_ ? graph_[id].parent : 0; }
195 [[nodiscard]] node
first_child(node
id)
const {
return graph_ ? graph_[id].child : 0; }
206 while(c != 0) {
if(graph_[c].
next_sibling == 0)
break; c = graph_[c].next_sibling; }
216 [[nodiscard]] node
prev_sibling(node
id)
const {
return graph_[id].prev_sibling; }
223 [[nodiscard]] node
next_sibling(node
id)
const {
return graph_[id].next_sibling; }
242 [[nodiscard]] uint32_t
depth(node
id)
const {
return graph_[id].depth; }
253 if(freed_.empty())
return static_cast<node
>(size_);
254 return freed_.front();
264 node
insert(
const data_type& data, node p_id, node sib = 0)
269 freed_.push_back(push_back_(std::forward<T>(data)));
273 std::construct_at(data_ + freed_.front(), std::forward<T>(data));
277 node
id = freed_.front(); freed_.pop_front();
278 bool back = sib == 0;
280 Node_& node = graph_[id];
281 Node_&
parent = graph_[p_id];
283 Node_& sibling = graph_[s_id];
286 node.next_sibling = node.prev_sibling = 0;
288 node.depth =
parent.depth + 1;
289 node.flags = Node_::valid;
292 if(s_id == 0)
return id;
296 node.next_sibling = sibling.next_sibling;
297 node.prev_sibling = s_id;
299 sibling.next_sibling = id;
303 node.next_sibling = s_id;
304 node.prev_sibling = sibling.prev_sibling;
306 sibling.prev_sibling = id;
319 node
insert(data_type&& data, node p_id, node sib = root)
324 freed_.push_back(push_back_(std::forward<T>(data)));
328 std::construct_at(data_ + freed_.front(), std::forward<T>(data));
332 node
id = freed_.front(); freed_.pop_front();
333 bool back = sib == root;
335 Node_& node = graph_[id];
336 Node_&
parent = graph_[p_id];
338 Node_& sibling = graph_[s_id];
341 node.next_sibling = node.prev_sibling = 0;
343 node.depth =
parent.depth + 1;
344 node.flags = Node_::valid;
347 if(s_id == 0)
return id;
351 node.next_sibling = sibling.next_sibling;
352 node.prev_sibling = s_id;
354 sibling.next_sibling = id;
358 node.next_sibling = s_id;
359 node.prev_sibling = sibling.prev_sibling;
361 sibling.prev_sibling = id;
367 void swap(node a, node b)
369 Node_& A = graph_[a];
370 Node_& B = graph_[b];
374 if(graph_[B.parent].child == a) graph_[B.parent].child = b;
375 if(graph_[A.parent].child == b) graph_[A.parent].child = a;
380 for(
int i = 0; i < size_; ++i)
382 if(
valid(i) ==
false)
continue;
385 std::destroy_at(data_ + i);
389 g_alloc_.deallocate(graph_, capacity_);
390 d_alloc_.deallocate(data_, capacity_);
391 capacity_ = 0; size_ = 0;
400 if(
id == root)
return;
403 Node_& erased = graph_[id];
405 freed_.push_back(
id);
406 std::destroy_at(data_ +
id);
409 graph_[erased.parent].child = erased.next_sibling;
412 if(erased.next_sibling) graph_[erased.next_sibling].prev_sibling = erased.prev_sibling;
413 if(erased.prev_sibling) graph_[erased.prev_sibling].next_sibling = erased.next_sibling;
416 node_queue stack{ erased.child };
417 while(stack.empty() ==
false)
419 node next = stack.front(); stack.pop_front();
420 Node_& child = graph_[next];
422 freed_.push_back(next);
423 std::destroy_at(data_ + next);
425 if(child.next_sibling) stack.push_front(child.next_sibling);
426 if(child.child) stack.push_front(child.child);
445 [[nodiscard]]
const data_type&
operator[](node
id)
const {
return data_[id]; }
456 template<
typename O = pre_order,
typename V>
469 size_t size_, capacity_;
484 node operator()(node
id)
486 while(!graph_.valid(current_) || current_ == root)
494 return id == graph_.graph_.size() ? 0 : id;
510 node operator()(node
id)
512 id = visit_queue_.back(); visit_queue_.pop_back();
513 Node_& current = graph_.graph_[id];
515 if(current.next_sibling) visit_queue_.push_back(current.next_sibling);
516 if(current.child) visit_queue_.push_front(current.child);
518 if(visit_queue_.empty())
return 0;
524 node_queue visit_queue_;
536 node operator()(node
id)
538 Node_& current = graph_.graph_[id];
540 if(current.next_sibling) visit_queue_.push_front(current.next_sibling);
541 if(current.child) visit_queue_.push_front(current.child);
543 if(visit_queue_.empty())
return 0;
544 node next = visit_queue_.front(); visit_queue_.pop_front();
550 node_queue visit_queue_;
562 node operator()(node
id)
564 if(
id == 0) visit_queue_.push_back(graph_.left_most(
id));
566 id = visit_queue_.front(); visit_queue_.pop_front();
567 Node_& current = graph_.graph_[id];
571 if(graph_.next_sibling(current.Sibling)) visit_queue_.push_back(current.parent);
572 visit_queue_.push_back(graph_.left_most(current.Sibling));
580 node_queue visit_queue_;
592 node operator()(node
id)
594 if(visit_queue_.empty()) visit_queue_.push_back(graph_.left_most(
id));
596 id = visit_queue_.front(); visit_queue_.pop_front();
597 if(
id == 0)
return id;
598 Node_& current = graph_.graph_[id];
600 visit_queue_.push_back(current.Sibling ? graph_.left_most(current.Sibling) : graph_.parent(
id));
607 node_queue visit_queue_;
614 template<
typename V,
typename O>
618 using visitor_type = V;
619 using order_type = O;
621 traverser(
directed_tree& graph, visitor_type& visitor) : graph_(graph), visitor_(visitor), order_(graph) { }
626 while(
id = order_(
id))
628 if(visitor_(graph_[
id],
id))
break;
634 visitor_type& visitor_;
Breadth first traversal.
Definition directed_tree.h:506
In-order traversal.
Definition directed_tree.h:558
Post-order traversal.
Definition directed_tree.h:588
Pre-order traversal.
Definition directed_tree.h:532
Visitor pattern for traversing the tree.
Definition directed_tree.h:616
Definition directed_tree.h:480
Class for creating a directed tree.
Definition directed_tree.h:39
node prev_sibling(node id) const
Get the previous sibling of a node. O(1)
Definition directed_tree.h:216
node parent(node id) const
Get the parent of a node. O(1)
Definition directed_tree.h:188
uint32_t depth(node id) const
Get the depth of a node.
Definition directed_tree.h:242
node first_child(node id) const
Get the first child of a node. O(1)
Definition directed_tree.h:195
node next_sibling(node id) const
Get the next sibling of a node. O(1)
Definition directed_tree.h:223
node left_most(node id) const
Get the left most child of a node. O(log(n))
Definition directed_tree.h:230
const data_type & operator[](node id) const
Constant getter for data associated with a node.
Definition directed_tree.h:445
node last_child(node id) const
Get the first child of a node. O(1)
Definition directed_tree.h:202
data_type & operator[](node id)
Getter for data associated with a node.
Definition directed_tree.h:438
node next_id() const
Get the next id that would be used if insert() were called.
Definition directed_tree.h:251
bool valid(node id) const
Check whether a node is valid. O(1)
Definition directed_tree.h:181
void erase(node id)
Erase a node in the tree. O(n)
Definition directed_tree.h:398
node insert(data_type &&data, node p_id, node sib=root)
Insert a node into the tree as a child of the provided node.
Definition directed_tree.h:319
void traverse(V &visitor)
Traverser-Visitor pattern for accessing the tree.
Definition directed_tree.h:457
directed_tree()
Default constructor, creates tree with empty root.
Definition directed_tree.h:156
node insert(const data_type &data, node p_id, node sib=0)
Insert a node into the tree as a child of the provided node.
Definition directed_tree.h:264