open-cpp-utils 0.0.1
Loading...
Searching...
No Matches
directed_tree.h
1// =====================================================================================================================
2// Copyright 2024 Medusa Slockbower
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// =====================================================================================================================
15
16#ifndef DIRECTEDGRAPH_H
17#define DIRECTEDGRAPH_H
18
19#include "template_utils.h"
20
21namespace open_cpp_utils
22{
23
31template<typename T>
33{
34// Forward Definitions =================================================================================================
35
36public:
37 class breadth_first;
38 class pre_order;
39 class in_order;
40 class post_order;
41
42private:
43 struct director;
44
45
46// Typedefs ============================================================================================================
47
48public:
49 using data_type = T;
50 using node = uint32_t;
51 using node_queue = std::deque<node>;
52
53private:
54 using hierarchy = std::vector<director>;
55 using storage = std::vector<data_type>;
56
57
58// Constants ===========================================================================================================
59
60public:
61 static constexpr constant_value<node, node(0)> root{};
62
63
64// Data Structures =====================================================================================================
65
66private:
67 struct director
68 {
69 enum flags
70 {
71 VALID = 0x0001
72 };
73
74 node parent, child, prev_sibling, next_sibling;
75 uint32_t flags, depth;
76
77 director() : parent(0), child(0), prev_sibling(0), next_sibling(0), flags(VALID) { }
78 };
79
80
81// Functions ===========================================================================================================
82
83public:
84
85// Constructors & Destructor ---------------------------------------------------------------------------------------
86
90 directed_tree() : graph_{ director() }, data_{ data_type() }, freed_{ } { }
91
92
93// Tree Navigation -------------------------------------------------------------------------------------------------
94
100 [[nodiscard]] node parent(node id) const { return graph_[id].parent; }
101
107 [[nodiscard]] node first_child(node id) const { return graph_[id].child; }
108
114 [[nodiscard]] node prev_sibling(node id) const { return graph_[id].prev_sibling; }
115
121 [[nodiscard]] node next_sibling(node id) const { return graph_[id].next_sibling; }
122
128 [[nodiscard]] node left_most(node id) const
129 {
130 node current = id;
131 while(id = first_child(current)) current = id;
132 return current;
133 }
134
140 [[nodiscard]] uint32_t depth(node id) const
141 {
142 uint32_t depth = 0;
143 while (id)
144 {
145 id = parent(id);
146 ++depth;
147 }
148 return depth;
149 }
150
151
152// Tree Modification ---------------------------------------------------------------------------------------------------
153
160 node insert(const data_type& data, node p_id)
161 {
162 if(freed_.empty())
163 {
164 freed_.push_back(static_cast<node>(graph_.size()));
165 graph_.push_back(director()); data_.push_back(data);
166 }
167
168 node id = freed_.front(); freed_.pop_front();
169 director& node = graph_[id];
170 director& parent = graph_[p_id];
171
172
173 if(parent.child)
174 {
175 director& nchild = graph_[parent.child];
176 node.prev_sibling = nchild.prev_sibling;
177 nchild.prev_sibling = id;
178
179 if(nchild.prev_sibling)
180 {
181 director& pchild = graph_[nchild.prev_sibling];
182 pchild.next_sibling = id;
183 }
184 }
185
186 // Setup node
187 node.parent = p_id;
188 node.next_sibling = parent.child;
189 node.child = 0;
190 node.flags = director::VALID;
191
192 // Set parent's child
193 parent.child = id;
194
195
196 data_[id] = data;
197
198 return id;
199 }
200
205 void erase(node id)
206 {
207 if(id == 0) return;
208
209 director& erased = graph_[id];
210 erased.Flags &= ~director::VALID;
211 freed_.push_back(id);
212
213 graph_[erased.parent].Child = erased.Sibling;
214
215 node_queue stack{ erased.Child };
216
217 while(stack.empty() == false)
218 {
219 node next = stack.front(); stack.pop_front();
220 director& child = graph_[next];
221 child.Flags &= ~director::VALID;
222 freed_.push_back(next);
223
224 if(child.Sibling) stack.push_front(child.Sibling);
225 if(child.Child) stack.push_front(child.Child);
226 }
227 }
228
229
230// Tree Access ---------------------------------------------------------------------------------------------------------
231
237 data_type& operator[](node id) { return data_[id]; }
238
244 [[nodiscard]] const data_type& operator[](node id) const { return data_[id]; }
245
246
247// Visitor Pattern -----------------------------------------------------------------------------------------------------
248
255 template<typename O = pre_order, typename V>
256 void traverse(V& visitor)
257 {
258 traverser<V, O> traverser(*this, visitor);
259 traverser();
260 }
261
262
263// Variables =======================================================================================================
264
265private:
266 hierarchy graph_;
267 storage data_;
268 node_queue freed_;
269
270
271// Navigation ======================================================================================================
272
273public:
274
279 {
280 public:
281 breadth_first(directed_tree& graph) : graph_(graph), visit_queue_(0) { }
282
283 node operator()(node node)
284 {
285 node = visit_queue_.back(); visit_queue_.pop_back();
286 director& current = graph_.graph_[node];
287
288 if(current.next_sibling) visit_queue_.push_back(current.next_sibling);
289 if(current.child) visit_queue_.push_front(current.child);
290
291 if(visit_queue_.empty()) return 0;
292 return node;
293 }
294
295 private:
296 directed_tree& graph_;
297 node_queue visit_queue_;
298 };
299
300
305 {
306 public:
307 pre_order(directed_tree& graph) : graph_(graph) { }
308
309 node operator()(node id)
310 {
311 director& current = graph_.graph_[id];
312
313 if(current.next_sibling) visit_queue_.push_front(current.next_sibling);
314 if(current.child) visit_queue_.push_front(current.child);
315
316 if(visit_queue_.empty()) return 0;
317 node next = visit_queue_.front(); visit_queue_.pop_front();
318 return next;
319 }
320
321 private:
322 directed_tree& graph_;
323 node_queue visit_queue_;
324 };
325
326
331 {
332 public:
333 in_order(directed_tree& graph) : graph_(graph) { }
334
335 node operator()(node node)
336 {
337 if(node == 0) visit_queue_.push_back(graph_.left_most(node));
338
339 node = visit_queue_.front(); visit_queue_.pop_front();
340 director& current = graph_.graph_[node];
341
342 if(current.Sibling)
343 {
344 if(graph_.next_sibling(current.Sibling)) visit_queue_.push_back(current.parent);
345 visit_queue_.push_back(graph_.left_most(current.Sibling));
346 }
347
348 return node;
349 }
350
351 private:
352 directed_tree& graph_;
353 node_queue visit_queue_;
354 };
355
356
361 {
362 public:
363 post_order(directed_tree& graph) : graph_(graph) { }
364
365 node operator()(node node)
366 {
367 if(visit_queue_.empty()) visit_queue_.push_back(graph_.left_most(node));
368
369 node = visit_queue_.front(); visit_queue_.pop_front();
370 if(node == 0) return node;
371 director& current = graph_.graph_[node];
372
373 visit_queue_.push_back(current.Sibling ? graph_.left_most(current.Sibling) : graph_.parent(node));
374
375 return node;
376 }
377
378 private:
379 directed_tree& graph_;
380 node_queue visit_queue_;
381 };
382
383
387 template<typename V, typename O>
389 {
390 public:
391 using visitor_type = V;
392 using order_type = O;
393
394 traverser(directed_tree& graph, visitor_type& visitor) : graph_(graph), visitor_(visitor), order_(graph) { }
395
396 void operator()()
397 {
398 node node = 0;
399 while(node = order_(node))
400 {
401 if(visitor_(graph_[node], node)) break;
402 }
403 }
404
405 private:
406 directed_tree& graph_;
407 visitor_type& visitor_;
408 order_type order_;
409 };
410};
411}
412
413#endif //DIRECTEDGRAPH_H
Breadth first traversal.
Definition directed_tree.h:279
In-order traversal.
Definition directed_tree.h:331
Post-order traversal.
Definition directed_tree.h:361
Pre-order traversal.
Definition directed_tree.h:305
Visitor pattern for traversing the tree.
Definition directed_tree.h:389
Class for creating a directed tree.
Definition directed_tree.h:33
void erase(node id)
Erase a node in the tree.
Definition directed_tree.h:205
node insert(const data_type &data, node p_id)
Insert a node into the tree as a child of the provided node.
Definition directed_tree.h:160
directed_tree()
Default constructor, creates tree with empty root.
Definition directed_tree.h:90
node prev_sibling(node id) const
Get the previous sibling of a node. O(1)
Definition directed_tree.h:114
node next_sibling(node id) const
Get the next sibling of a node. O(1)
Definition directed_tree.h:121
node parent(node id) const
Get the parent of a node. O(1)
Definition directed_tree.h:100
node first_child(node id) const
Get the first child of a node. O(1)
Definition directed_tree.h:107
node left_most(node id) const
Get the left most child of a node. O(log(n))
Definition directed_tree.h:128
uint32_t depth(node id) const
Get the depth of a node.
Definition directed_tree.h:140
void traverse(V &visitor)
Traverser-Visitor pattern for accessing the tree.
Definition directed_tree.h:256
const data_type & operator[](node id) const
Constant getter for data associated with a node.
Definition directed_tree.h:244
data_type & operator[](node id)
Getter for data associated with a node.
Definition directed_tree.h:237
Compile-time constant value.
Definition template_utils.h:34
Provides compile time evaluation utilities for templates and template packs.