Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_tree_node.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
43#ifndef TPL_TREE_H
44#define TPL_TREE_H
45
46#include <cassert>
47#include <stdexcept>
48#include <utility>
49#include <dlink.H>
50#include <ahDry.H>
51#include <ah-dry-mixin.H>
52#include <ahIterator.H>
53#include <ahFunction.H>
54#include <ahFunctional.H>
55#include <htlist.H>
56#include <tpl_dynListStack.H>
57#include <tpl_dynListQueue.H>
58#include <tpl_binNode.H>
59#include <ah-errors.H>
60
61#define ISROOT(p) ((p)->is_root())
62#define ISLEAF(p) ((p)->is_leaf())
63#define ISLEFTMOST(p) ((p)->is_leftmost())
64#define ISRIGHTMOST(p) ((p)->is_rightmost())
65
66#define SIBLING_LIST(p) ((p)->get_sibling_list())
67#define CHILD_LIST(p) ((p)->get_child_list())
68#define SIBLING_LINK(p) ((p)->get_sibling_list())
69#define LCHILD(p) ((p)->get_left_child())
70#define RSIBLING(p) ((p)->get_right_sibling())
71#define IS_UNIQUE_SIBLING(p) (SIBLING_LIST(p)->is_empty())
72
73namespace Aleph {
74
76template <class T>
77class Tree_Node; // Forward declaration for CRTP
78
112template <class T>
113class Tree_Node : public FunctionalMixin<Tree_Node<T>, Tree_Node<T> *>
114{
118
119 struct Flags
120 {
121 unsigned int is_root : 1;
122 unsigned int is_leaf : 1;
123 unsigned int is_leftmost : 1;
124 unsigned int is_rightmost : 1;
126 };
127
129
132
137
142
147
152
153public:
155
158 {
159 return get_data();
160 }
161
162 [[nodiscard]] constexpr const T &get_key() const noexcept
163 {
164 return get_data();
165 }
166
169 {
170 return data;
171 }
172
173 [[nodiscard]] constexpr const T &get_data() const noexcept
174 {
175 return data;
176 }
177
179 using key_type = T;
180
192 {
193 return &child;
194 }
195
208 {
209 return &sibling;
210 }
211
213 [[nodiscard]] constexpr bool is_root() const noexcept
214 {
215 return flags.is_root;
216 }
217
219 [[nodiscard]] constexpr bool is_leaf() const noexcept
220 {
221 return flags.is_leaf;
222 }
223
225 [[nodiscard]] constexpr bool is_leftmost() const noexcept
226 {
227 return flags.is_leftmost;
228 }
229
232 {
233 return flags.is_rightmost;
234 }
235
243 void set_is_root(bool value) noexcept
244 {
246 }
247
255 void set_is_leaf(bool value) noexcept
256 {
258 }
259
268 void set_is_leftmost(bool value) noexcept
269 {
271 }
272
280 void set_is_rightmost(bool value) noexcept
281 {
283 }
284
286 Tree_Node() = default;
287
289 Tree_Node(const T &d) : data(d)
290 { /* empty */
291 }
292
293 Tree_Node(T &&d) : data(std::move(d))
294 { /* empty */
295 }
296
299 {
300 if (is_leftmost())
301 return nullptr;
302
303 return left_link();
304 }
305
308 {
309 if (is_rightmost())
310 return nullptr;
311
312 return right_link();
313 }
314
317 {
318 if (is_leaf())
319 return nullptr;
320
321 return lower_link();
322 }
323
326 {
327 if (is_leaf())
328 return nullptr;
329
330 const Tree_Node *left_child = lower_link();
331
332 assert(ISLEFTMOST(left_child));
333
334 return left_child->left_link();
335 }
336
344 Tree_Node *get_child(const size_t i) const noexcept
345 {
347 for (size_t j = 0; c != nullptr and j < i; ++j)
348 c = c->get_right_sibling();
349
350 return c;
351 }
352
355 {
356 if (is_root())
357 return nullptr;
358
359 auto *p = const_cast<Tree_Node *>(this);
360 while (not ISLEFTMOST(p)) // go down to the leftmost node
361 p = p->left_link();
362
363 assert(not ISROOT(p));
364 assert(not CHILD_LIST(p)->is_empty());
365
366 return p->upper_link();
367 }
368
379 {
380 if (p == nullptr)
381 return;
382
383 assert(CHILD_LIST(p)->is_empty());
384 assert(SIBLING_LIST(p)->is_empty());
385 assert(p->is_rightmost() and p->is_leftmost() and p->is_root() and p->is_leaf());
386
387 if (this->is_root())
388 {
389 this->insert_tree_to_right(p);
390 return;
391 }
392
393 p->set_is_root(false);
394 p->set_is_leftmost(false);
395
397 if (old_next_node != nullptr)
398 {
399 assert(not this->is_rightmost());
400 p->set_is_rightmost(false);
401 }
402 else
403 {
404 assert(this->is_rightmost());
405 p->set_is_rightmost(true);
406 }
407
408 this->set_is_rightmost(false);
409 this->sibling.insert(SIBLING_LIST(p));
410 }
411
419 {
420 if (p == nullptr)
421 return;
422
423 ah_domain_error_if(this->is_root()) << "Cannot insert sibling of a root";
424
425 assert(CHILD_LIST(p)->is_empty());
426 assert(SIBLING_LIST(p)->is_empty());
428
429 p->set_is_root(false);
430 p->set_is_rightmost(false);
431
433 if (old_prev_node != nullptr)
434 {
435 assert(not this->is_leftmost());
436 p->set_is_leftmost(false);
437 }
438 else
439 { // this is the leftmost ==> p must become the first child
440 assert(this->is_leftmost());
441
442 Tree_Node *parent = this->get_parent();
443
444 // Find the tree root. To do so, we look for the leaf of this
445 Tree_Node *leaf = this;
446 while (not leaf->is_leaf())
447 {
448 leaf = leaf->get_left_child();
449 assert(leaf != nullptr);
450 }
451
452 Tree_Node *root = leaf->lower_link();
453 assert(root != nullptr);
454
455 Dlink tree = CHILD_LIST(root)->cut_list(CHILD_LIST(this));
456 tree.del();
457 CHILD_LIST(parent)->insert(CHILD_LIST(p));
458 p->set_is_leftmost(true);
459
460 assert(p->get_parent() == parent);
461 }
462
463 this->set_is_leftmost(false);
464 this->sibling.append(SIBLING_LIST(p));
465 }
466
472 {
473 if (p == nullptr)
474 return;
475
476 assert(CHILD_LIST(p)->is_empty());
477 assert(SIBLING_LIST(p)->is_empty());
478 assert(p->is_rightmost() and p->is_leftmost() and p->is_root() and p->is_leaf());
479
480 p->set_is_root(false);
481 if (this->is_leaf())
482 {
483 this->set_is_leaf(false);
484 CHILD_LIST(this)->insert(CHILD_LIST(p));
485 }
486 else
487 {
490 while (not leaf->is_leaf())
491 leaf = leaf->get_left_child();
492
493 Tree_Node *root = leaf->lower_link();
495 subtree.del();
496 CHILD_LIST(this)->insert(CHILD_LIST(p));
498 old_left_child->set_is_leftmost(false);
499 p->set_is_rightmost(false);
500 assert(p->get_right_sibling() == old_left_child);
501 assert(old_left_child->get_left_sibling() == p);
502 }
503 assert(p->is_leftmost());
504 }
505
511 {
512 if (p == nullptr)
513 return;
514
515 assert(CHILD_LIST(p)->is_empty());
516 assert(SIBLING_LIST(p)->is_empty());
517 assert(p->is_rightmost() and p->is_leftmost() and p->is_root() and p->is_leaf());
518
519 p->set_is_root(false);
520
521 if (this->is_leaf())
522 {
523 this->set_is_leaf(false);
524 CHILD_LIST(this)->insert(CHILD_LIST(p));
525 }
526 else
527 {
529 old_right_child_node->set_is_rightmost(false);
530 p->set_is_leftmost(false);
532 }
533 }
534
537 {
538 assert(this->is_root());
539 assert(tree != nullptr);
540 assert(tree->is_root() and tree->is_leftmost() and tree->is_rightmost());
541
542 tree->set_is_root(false);
543
544 if (this->is_leaf())
545 {
546 assert(CHILD_LIST(this)->is_empty() and SIBLING_LIST(this)->is_empty());
547 this->set_is_leaf(false);
548 CHILD_LIST(this)->splice(CHILD_LIST(tree));
549 }
550 else
551 {
552 Tree_Node *right_child = this->lower_link()->left_link();
553 right_child->set_is_rightmost(false);
554 tree->set_is_leftmost(false);
555 SIBLING_LINK(right_child)->splice(SIBLING_LINK(tree));
556 }
557
558 return this;
559 }
560
574 {
575 if (tree == nullptr)
576 return;
577
578 ah_domain_error_if(not this->is_root()) << "\"this\" is not root";
579
580 tree->set_is_leftmost(false);
582 if (old_next_tree != nullptr)
583 {
584 assert(not this->is_rightmost());
585 tree->set_is_rightmost(false);
586 }
587
588 this->set_is_rightmost(false);
589 SIBLING_LIST(this)->insert(SIBLING_LIST(tree));
590 }
591
594 {
595 if (is_leftmost())
596 return nullptr;
598 return left_link();
599 }
600
603 {
604 if (is_rightmost())
605 return nullptr;
606
608 return right_link();
609 }
610
614 {
615 ah_range_error_if(not is_leftmost()) << "\"this\" is not the leftmost tree in the forest";
616
617 return left_link();
618 }
619
621 template <template <typename> class Container = DynList>
623 {
625 for (auto t = const_cast<Tree_Node *>(this); t != nullptr; t = t->get_right_tree())
626 ret.append(t);
627 return ret;
628 }
629
631 template <typename Operation>
632 void for_each_child(Operation &op) const
633 {
634 for (Tree_Node *child = get_left_child(); child != nullptr; child = child->get_right_sibling())
635 op(child);
636 }
637
638 template <typename Operation>
639 void for_each_child(Operation &&op = Operation()) const
640 {
642 }
643
645 template <template <typename> class Container = DynList>
647 {
649 this->for_each_child([&ret_val](Tree_Node *p)
650 {
651 ret_val.append(p);
652 });
653 return ret_val;
654 }
655
657 template <template <typename> class Container = DynList>
659 {
661 this->for_each_child([&ret_val](Tree_Node *p)
662 {
663 ret_val.append(p->get_key());
664 });
665 return ret_val;
666 }
667
668private:
669 template <class Operation>
670 static bool preorder(const Tree_Node *root, Operation &op)
671 {
672 if (root == nullptr)
673 return true;
674
675 if (not op(root))
676 return false;
677
678 for (Tree_Node *child = root->get_left_child(); child != nullptr;
679 child = child->get_right_sibling())
680 if (not preorder(child, op))
681 return false;
682
683 return true;
684 }
685
686public:
688 template <class Operation>
690 {
691 return preorder(this, op);
692 }
693
694 template <class Operation>
695 bool traverse(Operation op) const
696 {
697 return const_cast<Tree_Node *>(this)->traverse(op);
698 }
699
700 template <class Op>
701 bool level_traverse(Op op)
702 {
704 q.put(this);
705 while (not q.is_empty())
706 {
707 Tree_Node *p = q.get();
708 if (not op(p))
709 return false;
710 p->for_each_child([&q](auto cptr)
711 {
712 q.put(cptr);
713 });
714 }
715 return true;
716 }
717
718 template <class Op>
719 bool level_traverse(Op op) const
720 {
721 return const_cast<Tree_Node *>(this)->level_traverse(op);
722 }
723
724 // Note: for_each(), all(), exists(), maps(), filter(), foldl(),
725 // fold(), partition(), take(), drop(), rev(), length() are now
726 // provided by FunctionalMixin<Tree_Node<T>, Tree_Node<T>*>
727
732 {
733 Tree_Node *curr = nullptr;
734
735 public:
736 Children_Iterator(const Tree_Node &p) noexcept : curr(p.get_left_child()) {}
737
738 Children_Iterator(Tree_Node &p) noexcept : curr(p.get_left_child()) {}
739
740 Children_Iterator(Tree_Node *p) noexcept : curr(p->get_left_child()) {}
741
743 : curr(it.curr)
744 {}
745
747 {
748 return curr != nullptr;
749 }
750
752 {
753 return curr;
754 }
755
757 {
758 ah_overflow_error_if(curr == nullptr) << "Children_Iterator::get_curr()";
759 return get_curr_ne();
760 }
761
763 {
765 }
766
767 void next()
768 {
769 ah_overflow_error_if(curr == nullptr) << "Children_Iterator::next()";
770 next_ne();
771 }
772 };
773
775 {
776 return Children_Iterator(*this);
777 }
778
786 {
791 {
793 };
794 };
795
803 {
804 Tree_Node *root = nullptr;
805 Tree_Node *curr = nullptr;
806 long pos = 0;
808
809 public:
811
812 void swap(Iterator &it) noexcept
813 {
814 std::swap(root, it.root);
815 std::swap(curr, it.curr);
816 std::swap(pos, it.pos);
817 s.swap(it.s);
818 }
819
821 {
822 // empty
823 }
824
826
827 Iterator(const Iterator &it) : root(it.root), curr(it.curr), pos(it.pos), s(it.s)
828 {
829 // empty
830 }
831
832 Iterator(Iterator &&it) noexcept : root(nullptr), curr(nullptr), pos(0), s()
833 {
834 swap(it);
835 }
836
838 {
839 it.swap(*this);
840 return *this;
841 }
842
844 {
845 s.empty();
846 pos = 0;
847 curr = root;
848 }
849
851 {
852 return curr != nullptr;
853 }
854
856 {
857 return curr;
858 }
859
861 {
862 ah_overflow_error_if(not has_curr()) << "Iterator overflow";
863 return get_curr_ne();
864 }
865
867 {
868 ++pos;
870 if (lchild == nullptr)
871 {
872 if (s.is_empty())
873 curr = nullptr;
874 else
875 curr = s.pop();
876
877 return;
878 }
879
880 for (auto p = curr->get_right_child(); p != lchild; p = p->get_left_sibling())
881 s.push(p);
882
883 curr = lchild;
884 }
885
886 void next()
887 {
888 ah_overflow_error_if(not has_curr()) << "Iterator overflow";
889 next_ne();
890 }
891
892 void end()
893 {
894 curr = nullptr;
895 s.empty();
896 pos = -1;
897 }
898
900 // has_curr() == true
901 [[nodiscard]] size_t get_pos() const
902 {
903 return pos;
904 }
905 };
906
908 {
909 return Iterator(const_cast<Tree_Node *>(this));
910 }
911
913};
914
924template <typename T>
925struct Tree_Node_Vtl : public Tree_Node<T>
926{
927 virtual ~Tree_Node_Vtl() = default;
928};
929
930template <class Node>
931static inline void clone_tree(Node *src, Node *tgt)
932{
933 using It = typename Node::Children_Iterator;
934 for (It it(src); it.has_curr(); it.next_ne())
935 tgt->insert_rightmost_child(new Node(it.get_curr()->get_key()));
936
937 using PItor = Pair_Iterator<It>;
938 for (PItor itor{It(*src), It(*tgt)}; itor.has_curr(); itor.next_ne())
939 {
940 auto p = itor.get_curr();
941 clone_tree(p.first, p.second);
942 }
943}
944
945template <class Node>
947{
948 if (root == nullptr)
949 return nullptr;
950 Node *ret = new Node(root->get_key());
952 return ret;
953}
954
955template <class Node>
956static inline void __tree_preorder_traversal(Node *root, const int &level, const int &child_index,
957 void (*visitFct)(Node *, int, int))
958{
959 (*visitFct)(root, level, child_index);
960 Node *child = root->get_left_child();
961 for (int i = 0; child != nullptr; ++i, child = child->get_right_sibling())
962 __tree_preorder_traversal(child, level + 1, i, visitFct);
963}
964
987template <class Node>
988inline void tree_preorder_traversal(Node *root, void (*visitFct)(Node *, int, int))
989{
990 ah_domain_error_if(not root->is_root()) << "root is not root";
991
993}
994
1017template <class Node>
1018inline void forest_preorder_traversal(Node *root, void (*visitFct)(Node *, int, int))
1019{
1020 ah_domain_error_if(not root->is_root()) << "root is not root";
1021
1022 for (/* nothing */; root != nullptr; root = root->get_right_tree())
1023 {
1024 assert(root->is_root());
1026 }
1027}
1028
1029template <class Node>
1030static inline void __tree_postorder_traversal(Node *node, const int &level, const int &child_index,
1031 void (*visitFct)(Node *, int, int))
1032{
1033 Node *child = node->get_left_child();
1034
1035 for (int i = 0; child not_eq nullptr; i++, child = child->get_right_sibling())
1036 __tree_postorder_traversal(child, level + 1, i, visitFct);
1037
1038 (*visitFct)(node, level, child_index);
1039}
1040
1062template <class Node>
1063inline void tree_postorder_traversal(Node *root, void (*visitFct)(Node *, int, int))
1064{
1066}
1067
1091template <class Node>
1092inline void forest_postorder_traversal(Node *root, void (*visitFct)(Node *, int, int))
1093{
1094 ah_domain_error_if(not root->is_leftmost()) << "root is not the leftmost node of forest";
1095
1096 ah_domain_error_if(not root->is_root()) << "root is not root";
1097
1098 for (/* nothing */; root not_eq nullptr; root = root->get_right_sibling())
1099 {
1100 assert(root->is_root());
1102 }
1103}
1104
1109template <class Node, class Eq>
1110inline bool are_tree_equal(Node *t1, Node *t2, Eq &eq)
1111{
1112 if (t1 == nullptr)
1113 return t2 == nullptr;
1114
1115 if (t2 == nullptr)
1116 return false;
1117
1118 if (not eq(t1->get_key(), t2->get_key()))
1119 return false;
1120
1121 try
1122 {
1123 return zipEq(t1->children_nodes(), t2->children_nodes())
1124 .all([&eq](auto p)
1125 {
1126 return are_tree_equal(p.first, p.second, eq);
1127 });
1128 }
1129 catch (const std::length_error &)
1130 {
1131 return false;
1132 }
1133}
1134
1135template <class Node, class Eq = std::equal_to<typename Node::key_type>>
1136inline bool are_tree_equal(Node *t1, Node *t2, Eq &&eq = Eq())
1137{
1138 return are_tree_equal<Node, Eq>(t1, t2, eq);
1139}
1140
1149template <class Node>
1151{
1152 if (root == nullptr)
1153 return;
1154
1155 // If `root` is the leftmost child of a live parent, its `child` field is
1156 // spine-linked to that parent (see the class-level note on the shared
1157 // spine trick): removing `root` must hand that spine slot to its right
1158 // sibling, promoted below to the new leftmost child. Captured before the
1159 // sibling list is touched; only usable once `root`'s own children have
1160 // been recursively destroyed (see below), so it is applied at the
1161 // `CHILD_LIST` cleanup near the end of this function, not here.
1162 Node *promoted_leftmost = nullptr;
1163
1165 {
1166 // `root` is about to be unlinked from its sibling list. If it was an
1167 // extremal sibling, the neighbor taking its place must inherit the
1168 // corresponding flag -- otherwise that neighbor is left with
1169 // is_rightmost()/is_leftmost() == false while actually being the new
1170 // extremum, so get_right_sibling()/get_left_sibling() no longer
1171 // short-circuit to nullptr and instead wrap around the remaining
1172 // circular sibling list, corrupting any get_right_sibling()-based
1173 // traversal (for_each_child(), Children_Iterator, ...) into an
1174 // infinite loop.
1175 if (root->is_rightmost())
1176 if (auto *new_last = root->get_left_sibling(); new_last != nullptr)
1177 new_last->set_is_rightmost(true);
1178
1179 if (root->is_leftmost())
1180 if (auto *new_first = root->get_right_sibling(); new_first != nullptr)
1181 {
1182 new_first->set_is_leftmost(true);
1183 // Only a child-of-a-parent's `child` field is spine-linked (a
1184 // top-level forest tree's `child` field is purely private, no
1185 // spine to hand over), and only when the promoted sibling is
1186 // itself a leaf can that hand-over be done with a single
1187 // Dlink::swap(): when the promoted sibling already has its own
1188 // children, its `child` field is already the head of its own
1189 // (unrelated) spine, and swap() would splice root's parent
1190 // directly to that spine's *other* end, orphaning the
1191 // promoted sibling's real children -- a separate, deeper,
1192 // pre-existing gap in destroy_tree() (reproducible even
1193 // without this fix: destroying any node that has its own
1194 // children while its parent survives already corrupts the
1195 // parent's child spine). Left as a known gap, tracked
1196 // separately, rather than risking new corruption here.
1197 if (not root->is_root() and new_first->is_leaf())
1198 promoted_leftmost = static_cast<Node *>(new_first);
1199 }
1200
1201 SIBLING_LIST(root)->del(); // no ==> remove from sibling list
1202 }
1203
1204 // traverse subtrees from right to left
1205 for (Node *p = static_cast<Node *>(root->get_right_child()); p != nullptr; /* nada */)
1206 {
1207 Node *to_delete = p; // backup subtree to delete
1208 p = static_cast<Node *>(p->get_left_sibling()); // advance to left sibling
1209 destroy_tree(to_delete); // recursively delete tree
1210 }
1211
1212 if (promoted_leftmost != nullptr)
1213 // root's own children are gone by now, so CHILD_LIST(root) is just its
1214 // spine pairing with its (live) parent; hand that slot to the promoted
1215 // sibling in one swap (promoted_leftmost is a leaf, i.e. its own
1216 // CHILD_LIST is empty, so Dlink::swap() simply relocates root's pairing
1217 // there instead of merging two unrelated non-empty lists).
1219 else if (root->is_leftmost()) // remove children list?
1220 CHILD_LIST(root)->del();
1221
1222 delete root;
1223}
1224
1236template <class Node>
1238{
1239 if (root == nullptr)
1240 return;
1241
1242 ah_domain_error_if(not root->is_leftmost()) << "root is not the leftmost tree of forest";
1243
1244 ah_domain_error_if(not root->is_root()) << "root is not root";
1245
1246 while (root != nullptr) // traverse trees from left to right
1247 {
1248 Node *to_delete = root; // backup root
1249 root = (Node *) root->get_right_sibling(); // advance to next tree
1250 SIBLING_LIST(to_delete)->del(); // remove from tree list
1251 destroy_tree(to_delete); // delete the tree
1252 }
1253}
1254
1261template <class Node>
1263{
1264 if (root == nullptr)
1265 return 0;
1266
1267 size_t temp_h, max_h = 0;
1268 for (Node *aux = root->get_left_child(); aux != nullptr; aux = aux->get_right_sibling())
1269 if ((temp_h = compute_height(aux)) > max_h)
1270 max_h = temp_h;
1271
1272 return max_h + 1;
1273}
1274
1275template <class Node>
1276static inline Node *__deway_search(Node *node, int path[], const int &idx, const size_t &size)
1277{
1278 if (node == nullptr)
1279 return nullptr;
1280
1281 ah_out_of_range_error_if(static_cast<size_t>(idx) >= size) << "index out of maximum range";
1282
1283 if (path[idx] < 0) // check whether the node has been reached
1284 return node;
1285 // advance to the next child path[0]
1286 Node *child = node->get_left_child();
1287 for (int i = 0; i < path[idx] and child != nullptr; ++i)
1288 child = child->get_right_sibling();
1289
1290 return __deway_search(child, path, idx + 1, size); // next level
1291}
1292
1306template <class Node>
1307inline Node *deway_search(Node *root, int path[], const size_t &size)
1308{
1309 for (int i = 0; root != nullptr; i++, root = root->get_right_sibling())
1310 if (path[0] == i)
1311 return __deway_search(root, path, 1, size);
1312
1313 return nullptr;
1314}
1315
1316template <class Node, class Equal>
1317inline static Node *__search_deway(Node *root, const typename Node::key_type &key,
1318 const size_t &current_level, int deway[], const size_t &size,
1319 size_t &n);
1320
1341template <class Node, class Equal = Aleph::equal_to<typename Node::key_type>>
1342inline Node *search_deway(Node *root, const typename Node::key_type &key, int deway[],
1343 const size_t &size, size_t &n)
1344{
1345 n = 1; // initial length value of the Dewey number
1346
1347 ah_overflow_error_if(size < n) << "there is no enough space for deway array";
1348
1349 for (int i = 0; root != nullptr; i++, root = root->get_right_sibling())
1350 {
1351 deway[0] = i;
1352 Node *result = __search_deway<Node, Equal>(root, key, 0, deway, size, n);
1353 if (result != nullptr)
1354 return result;
1355 }
1356
1357 return nullptr;
1358}
1359
1360template <class Node, class Equal>
1361inline static Node *__search_deway(Node *root, const typename Node::key_type &key,
1362 const size_t &current_level, int deway[], const size_t &size,
1363 size_t &n)
1364{
1365 ah_overflow_error_if(current_level >= size) << "there is no enough space for deway array";
1366
1367 if (root == nullptr)
1368 return nullptr;
1369
1370 if (Equal()(root->get_key(), key))
1371 {
1372 n = current_level + 1; // length of the deway array
1373 return root;
1374 }
1375
1376 Node *child = root->get_left_child();
1377 for (int i = 0; child != nullptr; i++, child = child->get_right_sibling())
1378 {
1379 ah_overflow_error_if(current_level + 1 >= size) << "there is no enough space for deway array";
1380 deway[current_level + 1] = i;
1381 Node *result = __search_deway<Node, Equal>(child, key, current_level + 1, deway, size, n);
1382
1383 if (result != nullptr)
1384 return result;
1385 }
1386
1387 return nullptr;
1388}
1389
1408template <class TNode, class BNode>
1410{
1411 if (root == nullptr)
1412 return BNode::NullPtr;
1413
1414 auto *result = new BNode(root->get_key());
1415 LLINK(result) = static_cast<BNode *>(forest_to_bin<TNode, BNode>(root->get_left_child()));
1416 RLINK(result) = forest_to_bin<TNode, BNode>(root->get_right_sibling());
1417
1418 return result;
1419}
1420
1421template <class TNode, class BNode>
1422inline static void insert_child(BNode *lnode, TNode *tree_node)
1423{
1424 if (lnode == BNode::NullPtr)
1425 return;
1426
1427 auto *child = new TNode(KEY(lnode));
1428 tree_node->insert_leftmost_child(child);
1429}
1430
1431template <class TNode, class BNode>
1432inline static void insert_sibling(BNode *rnode, TNode *tree_node)
1433{
1434 if (rnode == BNode::NullPtr)
1435 return;
1436
1437 auto *sibling = new TNode(KEY(rnode));
1438 tree_node->insert_right_sibling(sibling);
1439}
1440
1441template <class TNode, class BNode>
1442inline static void bin_to_tree(BNode *broot, TNode *troot)
1443{
1444 if (broot == BNode::NullPtr)
1445 return;
1446
1448 TNode *left_child = troot->get_left_child();
1449
1450 bin_to_tree(LLINK(broot), left_child);
1451
1453 TNode *right_sibling = troot->get_right_sibling();
1454
1456}
1457
1475template <class TNode, class BNode>
1477{
1478 if (broot == BNode::NullPtr)
1479 return nullptr;
1480
1481 auto *troot = new TNode(KEY(broot));
1483 return troot;
1484}
1485
1486} // end namespace Aleph
1487
1488#endif // TPL_TREE_H
CRTP Mixins for container functionality (DRY principle).
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:468
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:212
DRY (Don't Repeat Yourself) utilities and macros.
Standard functor implementations and comparison objects.
Functional programming utilities for Aleph-w containers.
Iterator traits and STL-compatible iterator wrappers.
#define STL_ALEPH_ITERATOR(Set_Name)
Definition ahIterator.H:208
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
size_t size_t int32_t value
Definition ca-c-api.h:116
Dynamic queue of elements of generic type T based on single linked list.
T & put(const T &data)
The type of element.
T get()
Remove the oldest item of the queue.
bool is_empty() const noexcept
Return true if this is empty.
Dynamic stack of elements of generic type T based on a singly linked list.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
Generic filter iterator wrapper.
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
CRTP Mixin providing functional programming operations.
Iterator that zips two other iterators.
auto get_curr() const
Get current pair (bounds-checked).
Iterator over the children of this.
Children_Iterator(const Children_Iterator &it) noexcept
Children_Iterator(Tree_Node &p) noexcept
Children_Iterator(const Tree_Node &p) noexcept
Children_Iterator(Tree_Node *p) noexcept
Tree_Node * get_curr_ne() const noexcept
Preorder iterator over a tree rooted at a Tree_Node.
Iterator(const Iterator &it)
bool has_curr() const noexcept
Iterator(Iterator &&it) noexcept
Iterator & operator=(Iterator it)
void swap(Iterator &it) noexcept
size_t get_pos() const
Return the current position of the iterator. Only valid if.
Iterator(Tree_Node *r=nullptr) noexcept
Tree_Node * get_curr() const
DynListStack< Tree_Node * > s
Tree_Node * get_curr_ne() const noexcept
Forward declaration used by CRTP helpers before the full node definition.
Tree_Node(const T &d)
Constructor with data value __data.
constexpr bool is_leftmost() const noexcept
Returns true if this is the leftmost node among its siblings.
bool traverse(Operation op)
Preorder traversal over all nodes executing op.
void set_is_root(bool value) noexcept
Sets the root flag.
Dlink * get_sibling_list() noexcept
Returns the embedded sibling-list link.
Tree_Node * left_link() const noexcept
Tree_Node * upper_link() const noexcept
static Tree_Node * sibling_to_Tree_Node(Dlink *link) noexcept
Tree_Node * join(Tree_Node *tree)
join tree as subtree of root this
Tree_Node * get_last_tree() const
Returns the rightmost tree of the forest containing this.
void insert_left_sibling(Tree_Node *p)
Inserts p as the left sibling of this.
Tree_Node * get_left_sibling() const noexcept
Returns the left sibling of this.
Tree_Node()=default
Empty constructor (undefined key).
constexpr const T & get_key() const noexcept
bool level_traverse(Op op) const
constexpr bool is_root() const noexcept
Returns true if this is the root of the general tree.
bool level_traverse(Op op)
T key_type
Generic data type stored in the node.
Tree_Node * get_left_child() const noexcept
Returns the leftmost child of this.
constexpr bool is_rightmost() const noexcept
Returns true if this is the rightmost node among its siblings.
Tree_Node * right_link() const noexcept
static bool preorder(const Tree_Node *root, Operation &op)
static Tree_Node * child_to_Tree_Node(Dlink *link) noexcept
Tree_Node * get_child(const size_t i) const noexcept
Returns the i-th child of this.
Container< Tree_Node * > trees() const
Return a list with all trees belonging to the forest.
void insert_leftmost_child(Tree_Node *p) noexcept
Inserts p as the leftmost child of this.
constexpr bool is_leaf() const noexcept
Returns true if this is a leaf node.
T & get_data() noexcept
Returns a modifiable reference to the node contents.
Dlink * get_child_list() noexcept
Returns the embedded child-list link.
Tree_Node * get_right_sibling() const noexcept
Returns the right sibling of this.
Tree_Node * get_left_tree() const noexcept
Returns the tree to the left of this.
void insert_rightmost_child(Tree_Node *p) noexcept
Inserts p as the rightmost child of this.
Tree_Node * lower_link() const noexcept
Children_Iterator children_it() const
Tree_Node * get_right_tree() const noexcept
Returns the tree to the right of this.
void insert_tree_to_right(Tree_Node *tree)
Insert tree to the right of this
constexpr const T & get_data() const noexcept
Tree_Node * get_parent() const noexcept
Returns the parent of this.
void set_is_leaf(bool value) noexcept
Sets the leaf flag.
Container< Tree_Node * > children_nodes() const
Returns a list with the child nodes of this.
void for_each_child(Operation &op) const
Visits each child of this and executes the operation on the child node.
bool traverse(Operation op) const
Tree_Node * get_right_child() const noexcept
Returns the rightmost child of this.
void insert_right_sibling(Tree_Node *p) noexcept
Inserts p to the right of this node.
T & get_key() noexcept
Returns a modifiable reference to the node contents.
Iterator get_it() const
Container< T > children() const
Returns a list with the contents of the children of this.
void set_is_leftmost(bool value) noexcept
Sets the leftmost-sibling flag.
void for_each_child(Operation &&op=Operation()) const
void set_is_rightmost(bool value) noexcept
Sets the rightmost-sibling flag.
void deway(Tree_Node< int > *p, int prefix[], const int &len, const size_t &dim)
Recursively compute and print Deway numbering for a tree node.
Definition deway.C:118
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4071
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
void forest_postorder_traversal(Node *root, void(*visitFct)(Node *, int, int))
Postorder traversal of a forest.
void destroy_tree(Node *root)
Destroys (frees memory) the tree whose root is root.
size_t compute_height(Node *root)
Computes the height of the tree root.
void tree_postorder_traversal(Node *root, void(*visitFct)(Node *, int, int))
Postorder traversal of a tree.
TNode * bin_to_forest(BNode *broot)
Converts a binary tree to its equivalent forest.
bool are_tree_equal(Node *t1, Node *t2, Eq &eq)
Returns true if t1 is equal to t2.
void destroy_forest(Node *root)
Destroys (frees memory) the forest whose first tree is root.
void forest_preorder_traversal(Node *root, void(*visitFct)(Node *, int, int))
Preorder traversal of a forest.
void tree_preorder_traversal(Node *root, void(*visitFct)(Node *, int, int))
Preorder traversal of a tree.
Node * search_deway(Node *root, const typename Node::key_type &key, int deway[], const size_t &size, size_t &n)
Searches key in a forest and computes the Dewey number of the node containing the key.
Node * deway_search(Node *root, int path[], const size_t &size)
Returns a node of a forest given its Dewey number.
BNode * forest_to_bin(TNode *root)
Converts a forest to its equivalent binary tree.
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
static Node * __deway_search(Node *node, int path[], const int &idx, const size_t &size)
static void insert_sibling(BNode *rnode, TNode *tree_node)
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
static void insert_child(BNode *lnode, TNode *tree_node)
static Node * __search_deway(Node *root, const typename Node::key_type &key, const size_t &current_level, int deway[], const size_t &size, size_t &n)
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zipEq(const Container1 &a, const Container2 &b)
Zip two containers; throw if lengths differ.
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
static void clone_tree(Node *src, Node *tgt)
static void bin_to_tree(BNode *broot, TNode *troot)
static void __tree_postorder_traversal(Node *node, const int &level, const int &child_index, void(*visitFct)(Node *, int, int))
static void __tree_preorder_traversal(Node *root, const int &level, const int &child_index, void(*visitFct)(Node *, int, int))
STL namespace.
Child iterator adapter used by generic iterator utilities.
Adapter that exposes a node's children through an Iterator type.
Children_Set(const Tree_Node &)
Children_Set(const Tree_Node &&)
Tree_Node variant with a virtual destructor.
virtual ~Tree_Node_Vtl()=default
#define RLINK(i, n)
#define LLINK(i, n)
DynArray< int > preorder
gsl_rng * r
Basic binary tree node definitions.
Dynamic queue implementation based on linked lists.
Dynamic stack implementation based on linked lists.
#define SIBLING_LINK(p)
#define SIBLING_LIST(p)
#define ISROOT(p)
#define CHILD_LIST(p)
#define IS_UNIQUE_SIBLING(p)
#define ISLEFTMOST(p)