Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_binNodeUtils.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
42#ifndef TPL_BINNODEUTILS_H
43#define TPL_BINNODEUTILS_H
44
45# include <ah-concepts.H>
46
47#include <ahFunction.H>
48#include <tpl_arrayStack.H>
49#include <tpl_arrayQueue.H>
50#include <tpl_dynListQueue.H>
51#include <bitArray.H>
52#include <tpl_dynDlist.H>
53#include <tpl_binNode.H>
54#include <ah-errors.H>
55# include <cassert>
56
57namespace Aleph {
58
74template <BinNodeLike Node>
75inline void assert_valid_tree_root([[maybe_unused]] const Node *root) noexcept
76{
77 assert((Node::NullPtr == nullptr or root != nullptr) and
78 "nullptr is not an empty tree for a node type with a sentinel; use Node::NullPtr");
79}
80template <BinNodeLike Node>
81inline void inorder_rec_helper(Node *node, const int &level, int &position,
82 void (*visitFct)(Node *, int, int))
83{
84 if (node == Node::NullPtr)
85 return;
86
87 inorder_rec_helper(LLINK(node), level + 1, position, visitFct);
88
89 (*visitFct)(node, level, position);
90 ++position;
91
92 inorder_rec_helper(RLINK(node), level + 1, position, visitFct);
93}
94
117template <BinNodeLike Node>
118inline int inOrderRec(Node *root, void (*visitFct)(Node *, int, int))
119{
121 int position = 0;
122 inorder_rec_helper(root, 0, position, visitFct);
123 return position;
124}
125
126template <BinNodeLike Node>
127inline void preorder_rec_helper(Node *p, const int &level, int &position,
128 void (*visitFct)(Node *, int, int))
129{
130 if (p == Node::NullPtr)
131 return;
132
133 (*visitFct)(p, level, position);
134 ++position;
135
136 preorder_rec_helper(LLINK(p), level + 1, position, visitFct);
137 preorder_rec_helper(RLINK(p), level + 1, position, visitFct);
138}
139
162template <BinNodeLike Node>
163inline int preOrderRec(Node *root, void (*visitFct)(Node *, int, int))
164{
166 int position = 0;
167 preorder_rec_helper(root, 0, position, visitFct);
168 return position;
169}
170
171template <BinNodeLike Node>
172inline void postorder_rec_helper(Node *node, const int &level, int &position,
173 void (*visitFct)(Node *, int, int))
174{
175 if (node == Node::NullPtr)
176 return;
177
178 postorder_rec_helper(LLINK(node), level + 1, position, visitFct);
179 postorder_rec_helper(RLINK(node), level + 1, position, visitFct);
180
181 (*visitFct)(node, level, position);
182 ++position;
183}
184
207template <BinNodeLike Node>
208inline int postOrderRec(Node *root, void (*visitFct)(Node *, int, int))
209{
211 int position = 0;
212 postorder_rec_helper(root, 0, position, visitFct);
213 return position;
214}
215
231template <class Node>
233{
234 template <class Op>
235 static void for_each_inorder(Node *root, Op &&op)
236 {
237 if (root == Node::NullPtr)
238 return;
239
240 for_each_inorder(LLINK(root), std::forward<Op>(op));
241 op(root);
242 for_each_inorder(RLINK(root), std::forward<Op>(op));
243 }
244
245public:
247 template <class Op>
248 void traverse(Node *root, Op &&op) const
249 {
250 for_each_inorder(root, std::forward<Op>(op));
251 }
252
254 template <class Op>
255 void operator () (Node *root, Op &op) const
256 {
258 }
259
261 template <class Op>
262 void operator () (Node *root, Op &&op) const
263 {
264 for_each_inorder(root, std::forward<Op>(op));
265 }
266};
267
274template <BinNodeLike Node, class Op>
275inline void for_each_in_order(Node *root, Op &&op)
276{
277 return For_Each_In_Order<Node>().traverse(root, std::forward<Op>(op));
278}
279
296template <class Node>
298{
299 template <class Op>
300 static void preorder(Node *root, Op &&op)
301 {
302 if (root == Node::NullPtr)
303 return;
304
305 op(root);
306 preorder(LLINK(root), std::forward<Op>(op));
307 preorder(RLINK(root), std::forward<Op>(op));
308 }
309
310public:
312 template <class Op>
313 void traverse(Node *root, Op &&op) const
314 {
315 return preorder(root, std::forward<Op>(op));
316 }
317
319 template <class Op>
320 void operator () (Node *root, Op &op) const
321 {
322 preorder(root, op);
323 }
324
326 template <class Op>
327 void operator () (Node *root, Op &&op = Op()) const
328 {
329 preorder(root, std::forward<Op>(op));
330 }
331};
332
339template <BinNodeLike Node, class Op>
341{
342 For_Each_Preorder<Node>().traverse(root, std::forward<Op>(op));
343}
344
360template <class Node>
362{
363 template <class Op>
364 static void postorder(Node *root, Op &&op)
365 {
366 if (root == Node::NullPtr)
367 return;
368
369 postorder(LLINK(root), std::forward<Op>(op));
370 postorder(RLINK(root), std::forward<Op>(op));
371 op(root);
372 }
373
374public:
376 template <class Op>
377 void traverse(Node *root, Op &&op) const
378 {
379 return postorder(root, std::forward<Op>(op));
380 }
381
383 template <class Op>
384 void operator () (Node *root, Op &op) const
385 {
386 postorder(root, op);
387 }
388
390 template <class Op>
391 void operator () (Node *root, Op &&op = Op()) const
392 {
393 postorder(root, std::forward<Op>(op));
394 }
395};
396
403template <BinNodeLike Node, class Op>
405{
406 For_Each_Postorder<Node>().traverse(root, std::forward<Op>(op));
407}
408
409template <BinNodeLike Node>
411{
412 if (root == Node::NullPtr)
413 return;
414
415 acc.append(root);
416 prefix(LLINK(root), acc);
417 prefix(RLINK(root), acc);
418}
419
420template <BinNodeLike Node>
422{
423 if (root == Node::NullPtr)
424 return;
425
426 infix(LLINK(root), acc);
427 acc.append(root);
428 infix(RLINK(root), acc);
429}
430
431template <BinNodeLike Node>
433{
434 if (root == Node::NullPtr)
435 return;
436
437 suffix(LLINK(root), acc);
438 suffix(RLINK(root), acc);
439 acc.append(root);
440}
441
449template <BinNodeLike Node>
456
464template <BinNodeLike Node>
471
479template <BinNodeLike Node>
486
493template <BinNodeLike Node>
494inline size_t compute_cardinality_rec(Node *root) noexcept
495{
497 if (root == Node::NullPtr)
498 return 0;
499
501}
502
504template <BinNodeLike Node>
505inline size_t size(Node *root) noexcept
506{
508}
509
516template <BinNodeLike Node>
517inline size_t computeHeightRec(Node *root) noexcept
518{
520 if (root == Node::NullPtr)
521 return 0;
522
523 const size_t left_height = computeHeightRec(LLINK(root));
524 const size_t right_height = computeHeightRec(RLINK(root));
525
526 return 1 + std::max(left_height, right_height);
527}
528
537template <BinNodeLike Node>
538inline void destroyRec(Node *&root) noexcept
539{
541 if (root == Node::NullPtr)
542 return;
543
546 delete root;
547 root = Node::NullPtr;
548}
549
562template <BinNodeLike Node>
563inline void callKeyDestructorsRec(Node *&root) noexcept
564{
566 if (root == Node::NullPtr)
567 return;
568
569 using Key = typename Node::key_type;
570
573 root->get_key().~Key();
574 root = Node::NullPtr;
575}
576
584template <BinNodeLike Node>
586{
588 if (root == Node::NullPtr)
589 return Node::NullPtr;
590
591 Node *tgt_root = new Node(*root);
592
593 try
594 {
597 }
598 catch (...)
599 {
600 assert(RLINK(tgt_root) == Node::NullPtr);
601
602 if (LLINK(tgt_root) != Node::NullPtr)
603 destroyRec(LLINK(tgt_root)); // TODO: diff de Node*&
604
605 delete tgt_root;
606
607 throw;
608 }
609
610 return tgt_root;
611}
612
623template <BinNodeLike Node>
624inline bool areSimilar(Node *t1, Node *t2) noexcept
625{
626 if (t1 == t2) // that include the case when t1 and t2 are the same
627 // or both are Node::NullPtr
628 return true;
629
630 if (t1 == Node::NullPtr or t2 == Node::NullPtr)
631 return false;
632
634}
635
647template <BinNodeLike Node, class Equal>
648inline bool areEquivalents(Node *t1, Node *t2, Equal &op) noexcept
649{
650 if (t1 == t2)
651 return true;
652
653 if (t1 == Node::NullPtr or t2 == Node::NullPtr)
654 return false;
655
656 if (not op(KEY(t1), KEY(t2)))
657 return false;
658
660}
661
663template <BinNodeLike Node, class Equal = std::equal_to<typename Node::key_type>>
664inline bool areEquivalents(Node *t1, Node *t2, Equal &&op = Equal()) noexcept
665{
666 return areEquivalents(t1, t2, op);
667}
668
685template <BinNodeLike Node>
686inline void levelOrder(Node *root, void (*visitFct)(Node *, int, bool))
687{
689 if (root == Node::NullPtr)
690 return;
691
693 queue.put(std::pair<Node *, bool>(root, bool()));
694
695 for (int pos = 0; not queue.is_empty(); pos++)
696 {
697 std::pair<Node *, bool> pr = queue.get();
698 Node *&p = pr.first;
699
700 (*visitFct)(p, pos, pr.second);
701
702 if (LLINK(p) != Node::NullPtr)
703 queue.put(std::pair<Node *, bool>(LLINK(p), true));
704
705 if (RLINK(p) != Node::NullPtr)
706 queue.put(std::pair<Node *, bool>(RLINK(p), false));
707 }
708}
709
725template <BinNodeLike Node, class Operation>
727{
728 if (root == Node::NullPtr)
729 return true;
730
732 queue.put(root);
733 while (not queue.is_empty())
734 {
735 Node *p = queue.get();
736 if (not operation(p))
737 return false;
738
739 if (LLINK(p) != Node::NullPtr)
740 queue.put(LLINK(p));
741
742 if (RLINK(p) != Node::NullPtr)
743 queue.put(RLINK(p));
744 }
745 return true;
746}
747
748template <BinNodeLike Node, class Operation>
753
769template <template <class> class Node, typename Key>
771 const DynArray<Key> &inorder, long l_i, long r_i)
772{
773 if (l_p > r_p)
774 {
775 assert(l_i > r_i);
776 return Node<Key>::NullPtr;
777 }
778
779 assert(r_p - l_p == r_i - l_i);
780
781 auto *root = new Node<Key>(preorder[l_p]);
782 if (r_p == l_p)
783 return root;
784
785 assert(l_i <= r_i);
786
787 // Find root key position in inorder array
788 int i = -1;
789 for (int j = l_i; j <= r_i; ++j)
790 if (inorder[j] == preorder[l_p])
791 {
792 i = j - l_i;
793 break;
794 }
795
796 // Validate that root key was found in inorder array
797 ah_domain_error_if(i < 0) << "build_tree: root key not found in inorder array (corrupted input)";
798
799 assert(i <= r_i - l_i);
800
801 LLINK(root) = build_tree<Node, Key>(preorder, l_p + 1, l_p + i, inorder, l_i, l_i + (i - 1));
802 RLINK(root) = build_tree<Node, Key>(preorder, l_p + i + 1, r_p, inorder, l_i + i + 1, r_i);
803 return root;
804}
805
806template <template <class> class Node, typename Key>
807inline Node<Key> *build_postorder(const DynArray<Key> &post, long lp, long rp,
808 const DynArray<Key> &in, long li, long ri)
809{
810 assert(rp - lp == ri - li);
811 if (lp > rp)
812 return Node<Key>::NullPtr;
813
814 auto *root = new Node<Key>(post[rp]);
815
816 // Search in inorder array the index of root
817 int i = li;
818 for (; i <= ri; ++i)
819 if (in[i] == post[rp])
820 break;
821
822 // Validate that root key was found in inorder array
824 << "build_postorder: root key not found in inorder array (corrupted input)";
825
826 assert(i <= ri);
827
828 LLINK(root) = build_postorder<Node, Key>(post, lp, lp + (i - li) - 1, in, li, i - 1);
829 RLINK(root) = build_postorder<Node, Key>(post, rp - (ri - i), rp - 1, in, i + 1, ri);
830 return root;
831}
832
833template <BinNodeLike Node>
834inline void compute_nodes_in_level_helper(Node *root, long level, const long current_level,
836{
837 if (root == Node::NullPtr)
838 return;
839
840 if (current_level == level)
841 {
842 level_list.append(root);
843 return; // it is not worth descending further
844 }
845
846 compute_nodes_in_level_helper(LLINK(root), level, current_level + 1, level_list);
847 compute_nodes_in_level_helper(RLINK(root), level, current_level + 1, level_list);
848}
849
858template <BinNodeLike Node>
860{
861 DynDlist<Node *> list;
862 compute_nodes_in_level_helper(root, level, 0, list);
863 return list;
864}
865
886template <BinNodeLike Node>
887inline void inOrderThreaded(Node *root, void (*visitFct)(Node *))
888{
889 if (root == Node::NullPtr)
890 return;
891
892 Node *p = root, *r = Node::NullPtr;
893 while (p != Node::NullPtr)
894 {
895 Node *q = LLINK(p);
896 if (q == Node::NullPtr)
897 { // No left branch ==> visit p
898 (*visitFct)(p);
899 r = p;
900 p = RLINK(p);
901 continue;
902 }
903
904 // Move towards the rightmost node of the left branch
905 while (q != r and RLINK(q) != Node::NullPtr)
906 q = RLINK(q);
907
908 if (q != r) // Does p have a predecessor?
909 { // yes ==> leave a thread in order to later come back and visit p
910 RLINK(q) = p; // place the thread here
911 p = LLINK(p); // keep descending on the left
912 continue;
913 }
914
915 (*visitFct)(p);
916
917 RLINK(q) = Node::NullPtr; // delete thread
918 r = p;
919 p = RLINK(p); // advance to the right branch
920 }
921}
922
943template <BinNodeLike Node>
944inline void preOrderThreaded(Node *node, void (*visitFct)(Node *))
945{
946 if (node == Node::NullPtr)
947 return;
948
949 Node *p = node, *r = Node::NullPtr;
950 while (p != Node::NullPtr)
951 {
952 Node *q = LLINK(p);
953
954 if (q == Node::NullPtr)
955 {
956 (*visitFct)(p);
957 r = p;
958 p = RLINK(p);
959 continue;
960 }
961
962 // advance towards the rightmost node of the left branch
963 while (q != r and RLINK(q) != Node::NullPtr)
964 q = RLINK(q);
965
966 if (q != r)
967 {
968 RLINK(q) = p;
969 (*visitFct)(p);
970 p = LLINK(p);
971 continue;
972 }
973
974 RLINK(q) = Node::NullPtr; /* delete thread */
975 r = p;
976 p = RLINK(p); /* advance to right branch */
977 }
978}
979
980template <BinNodeLike Node>
981inline size_t internal_path_length_helper(Node *p, const size_t &level) noexcept
982{
983 if (p == Node::NullPtr)
984 return 0;
985
986 return level + internal_path_length_helper(LLINK(p), level + 1) +
987 internal_path_length_helper(RLINK(p), level + 1);
988}
989
997template <BinNodeLike Node>
998inline size_t internal_path_length(Node *p) noexcept
999{
1001 return internal_path_length_helper(p, 0);
1002}
1003
1017template <BinNodeLike Node>
1018inline void tree_to_bits(Node *root, BitArray &array)
1019{
1020 if (root == Node::NullPtr)
1021 {
1022 array.push(1);
1023 return;
1024 }
1025
1026 array.push(0);
1027 tree_to_bits(LLINK(root), array);
1028 tree_to_bits(RLINK(root), array);
1029}
1030
1044template <BinNodeLike Node>
1046{
1049 return ret_val;
1050}
1051
1059template <BinNodeLike Node>
1060inline std::string code(Node *root)
1061{
1062 const BitArray bits = tree_to_bits(root);
1063 const size_t n = bits.size();
1064 std::string str;
1065 str.reserve(n);
1066 for (size_t i = 0; i < n; ++i)
1067 str.push_back(bits(i) ? 'b' : 'a');
1068
1069 return str;
1070}
1071
1072template <BinNodeLike Node>
1073inline Node *bits_to_tree_helper(const BitArray &array, int &i)
1074{
1075 // Bounds check: ensure we don't read past the end of the bit array
1076 ah_domain_error_if(i >= static_cast<int>(array.size()))
1077 << "bits_to_tree_helper: bit array index out of bounds (malformed input)";
1078
1079 if (const int bit = array.read_bit(i++); bit == 1)
1080 return Node::NullPtr;
1081
1082 Node *p = new Node;
1083 Node *left = Node::NullPtr;
1084 Node *right = Node::NullPtr;
1085 try
1086 {
1087 left = bits_to_tree_helper<Node>(array, i);
1088 right = bits_to_tree_helper<Node>(array, i);
1089 }
1090 catch (...)
1091 {
1092 destroyRec(left);
1093 destroyRec(right);
1094 delete p;
1095 throw;
1096 }
1097
1098 LLINK(p) = left;
1099 RLINK(p) = right;
1100
1101 return p;
1102}
1103
1117template <BinNodeLike Node>
1118inline Node *bits_to_tree(const BitArray &array, int idx = 0)
1119{
1120 return bits_to_tree_helper<Node>(array, idx);
1121}
1122
1140template <BinNodeLike Node>
1141inline void save_tree_keys_in_prefix(Node *root, std::ostream &output)
1142{
1143 if (root == Node::NullPtr)
1144 return;
1145
1146 output << root->get_key() << " ";
1147
1150}
1151
1162template <BinNodeLike Node>
1163inline void load_tree_keys_in_prefix(Node *root, std::istream &input)
1164{
1165 if (root == Node::NullPtr)
1166 return;
1167
1168 input >> root->get_key();
1169 ah_runtime_error_if(not input) << "load_tree_keys_in_prefix: input stream error";
1170
1173}
1174
1189template <BinNodeLike Node>
1190inline void save_tree(Node *root, std::ostream &output)
1191{
1194 prefix.save(output);
1196}
1197
1209template <BinNodeLike Node>
1210inline Node *load_tree(std::istream &input)
1211{
1213 prefix.load(input);
1215 try
1216 {
1218 }
1219 catch (...)
1220 {
1221 destroyRec(root); // Cleanup partially loaded tree on exception
1222 throw;
1223 }
1224 return root;
1225}
1226
1227template <BinNodeLike Node, class Get_Key>
1228inline void put_tree_keys_in_array(Node *root, std::ostream &out)
1229{
1230 if (root == Node::NullPtr)
1231 return;
1232
1233 const std::string str = Get_Key()(root);
1234 out << "\"";
1235 for (const char ch : str)
1236 {
1237 switch (ch)
1238 {
1239 case '\n':
1240 out << "\\n";
1241 break;
1242 case '\t':
1243 out << "\\t";
1244 break;
1245 case '\\':
1246 out << "\\\\";
1247 break;
1248 case '"':
1249 out << "\\\"";
1250 break;
1251 default:
1252 out << ch;
1253 break;
1254 }
1255 }
1256 out << "\", ";
1257
1260}
1261
1262template <BinNodeLike Node, class Load_Key>
1263inline void load_tree_keys_from_array(Node *root, const char *keys[], int &idx)
1264{
1265 if (root == Node::NullPtr)
1266 return;
1267
1268 if (Load_Key()(root, keys[idx]))
1269 ++idx;
1270
1273}
1274
1303template <BinNodeLike Node, class Get_Key>
1304inline void save_tree_in_array_of_chars(Node *root, const std::string &array_name,
1305 std::ostream &output)
1306{
1309 prefix.save_in_array_of_chars(array_name + "_cdp", output);
1310 output << "const char * " << array_name << "_k[] = { " << '\n';
1312 output << "nullptr };" << '\n';
1313}
1314
1344template <BinNodeLike Node, class Load_Key>
1345inline Node *load_tree_from_array(const unsigned char bits[], const size_t &num_bits,
1346 const char *keys[])
1347{
1349 prefix.load_from_array_of_chars(bits, num_bits);
1351 int i = 0;
1353 return root;
1354}
1355
1356template <BinNodeLike Node, class Compare>
1357inline bool check_bst_range(Node *p, const typename Node::key_type *min_key,
1358 const typename Node::key_type *max_key, const Compare &cmp)
1359{
1360 if (p == Node::NullPtr)
1361 return true;
1362
1363 const auto &key = KEY(p);
1364 if (min_key != nullptr and not less_or_equal_than(*min_key, key, cmp))
1365 return false;
1366 if (max_key != nullptr and not less_or_equal_than(key, *max_key, cmp))
1367 return false;
1368
1369 return check_bst_range<Node, Compare>(LLINK(p), min_key, &key, cmp) and
1370 check_bst_range<Node, Compare>(RLINK(p), &key, max_key, cmp);
1371}
1372
1382template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1383inline bool check_bst(Node *p, const Compare &cmp = Compare())
1384{
1386 return check_bst_range<Node, Compare>(p, nullptr, nullptr, cmp);
1387}
1388
1400template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1402 const Compare &cmp = Compare())
1403{
1404 if (l > r)
1405 return Node::NullPtr;
1406
1407 Node *root = new Node(preorder[l]);
1408
1409 if (l == r)
1410 return root;
1411
1412 int first_greater = l + 1;
1414 ++first_greater;
1415
1418
1419 return root;
1420}
1421
1423enum ThreeWayCmp : int
1424{
1425 CmpLess = -1,
1427 CmpGreater = 1
1429
1441template <typename T, class Compare = Aleph::less<T>>
1442inline ThreeWayCmp three_way_compare(const T &a, const T &b, const Compare &cmp = Compare()) noexcept
1443{
1444 if (cmp(a, b))
1445 return CmpLess;
1446 if (cmp(b, a))
1447 return CmpGreater;
1448 return CmpEqual;
1449}
1450
1465template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1466[[nodiscard]] inline Node *searchInBinTree(Node *root, const typename Node::key_type &key,
1467 const Compare &cmp = Compare()) noexcept
1468{
1470 Node *candidate = nullptr; // Tracks potential match when going right
1471
1472 while (root != Node::NullPtr)
1473 {
1476
1477 if (cmp(key, KEY(root))) // key < root: go left
1478 root = LLINK(root);
1479 else // key >= root: go right, mark as candidate
1480 {
1481 candidate = root;
1482 root = RLINK(root);
1483 }
1484 }
1485
1486 // Optimistic check: if candidate exists and key == candidate, return it
1487 if (candidate != nullptr and not cmp(KEY(candidate), key)) [[unlikely]]
1488 return candidate;
1489
1490 return Node::NullPtr;
1491}
1492
1501template <BinNodeLike Node>
1502[[nodiscard]] inline Node *find_min(Node *root) noexcept
1503{
1505 assert(root != Node::NullPtr && "find_min called on empty tree");
1506 while (LLINK(root) != Node::NullPtr)
1507 root = LLINK(root);
1508
1509 return root;
1510}
1511
1520template <BinNodeLike Node>
1521[[nodiscard]] inline Node *find_max(Node *root) noexcept
1522{
1524 assert(root != Node::NullPtr && "find_max called on empty tree");
1525 while (RLINK(root) != Node::NullPtr)
1526 root = RLINK(root);
1527
1528 return root;
1529}
1530
1539template <BinNodeLike Node>
1540inline Node *find_successor(Node *p, Node *&pp) noexcept
1541{
1542 assert(p != Node::NullPtr);
1543 assert(RLINK(p) != Node::NullPtr);
1544
1545 pp = p;
1546 p = RLINK(p);
1547 while (LLINK(p) != Node::NullPtr)
1548 {
1549 pp = p;
1550 p = LLINK(p);
1551 }
1552
1553 return p;
1554}
1555
1564template <BinNodeLike Node>
1565inline Node *find_predecessor(Node *p, Node *&pp) noexcept
1566{
1567 assert(p != Node::NullPtr);
1568 assert(LLINK(p) != Node::NullPtr);
1569
1570 pp = p;
1571 p = LLINK(p);
1572
1573 while (RLINK(p) != Node::NullPtr)
1574 {
1575 pp = p;
1576 p = RLINK(p);
1577 }
1578
1579 return p;
1580}
1581
1594template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1595inline Node *search_parent(Node *root, const typename Node::key_type &key, Node *&parent,
1596 const Compare &cmp = Compare()) noexcept
1597{
1599 assert((LLINK(parent) == root) or (RLINK(parent) == root));
1600 assert(root != Node::NullPtr);
1601
1602 while (true)
1603 {
1604 const auto c = three_way_compare(key, KEY(root), cmp);
1605 if (c == CmpLess) [[likely]]
1606 {
1607 if (LLINK(root) == Node::NullPtr)
1608 return root;
1609
1610 parent = root;
1611 root = LLINK(root);
1612 }
1613 else if (c == CmpGreater) [[likely]]
1614 {
1615 if (RLINK(root) == Node::NullPtr)
1616 return root;
1617
1618 parent = root;
1619 root = RLINK(root);
1620 }
1621 else [[unlikely]]
1622 return root;
1623 }
1624}
1625
1644template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1645inline Node *search_rank_parent(Node *root, const typename Node::key_type &key,
1646 const Compare &cmp = Compare()) noexcept
1647{
1649 assert(root != Node::NullPtr);
1650
1651 while (true)
1652 if (const auto &root_key = KEY(root); cmp(key, root_key))
1653 {
1654 if (LLINK(root) == Node::NullPtr)
1655 return root;
1656
1657 root = LLINK(root);
1658 }
1659 else if (cmp(root_key, key))
1660 {
1661 if (RLINK(root) == Node::NullPtr)
1662 return root;
1663
1664 root = RLINK(root);
1665 }
1666 else
1667 return root;
1668}
1669
1682template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1683inline Node *insert_in_bst(Node *&r, Node *p, const Compare &cmp = Compare()) noexcept
1684{
1686 if (r == Node::NullPtr) [[unlikely]]
1687 return r = p;
1688
1689 const auto &pk = KEY(p);
1690 const auto &rk = KEY(r);
1691
1692 if (cmp(pk, rk))
1694 if (cmp(rk, pk))
1696
1697 [[unlikely]] return Node::NullPtr;
1698}
1699
1712template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1713inline Node *insert_dup_in_bst(Node *&root, Node *p, const Compare &cmp = Compare()) noexcept
1714{
1716 if (root == Node::NullPtr) [[unlikely]]
1717 return root = p;
1718
1719 const auto &pk = KEY(p);
1720 const auto &rk = KEY(root);
1721
1722 if (cmp(pk, rk))
1723 return insert_dup_in_bst(LLINK(root), p, cmp);
1724
1725 return insert_dup_in_bst(RLINK(root), p, cmp);
1726}
1727
1742template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1743inline Node *search_or_insert_in_bst(Node *&r, Node *p, const Compare &cmp = Compare()) noexcept
1744{
1746 if (r == Node::NullPtr) [[unlikely]]
1747 return r = p;
1748
1749 const auto &pk = KEY(p);
1750 const auto &rk = KEY(r);
1751
1752 if (cmp(pk, rk))
1754 if (cmp(rk, pk))
1756
1757 [[unlikely]] return r;
1758}
1759
1760template <BinNodeLike Node, class Compare>
1761inline bool split_key_rec_helper(Node *root, const typename Node::key_type &key, Node *&ts,
1762 Node *&tg, Compare &cmp) noexcept
1763{
1764 if (root == Node::NullPtr)
1765 { // key is not in the tree ==> split will succeed
1766 ts = tg = Node::NullPtr;
1767 return true;
1768 }
1769
1770 if (cmp(key, KEY(root)))
1771 {
1773 {
1774 tg = root;
1775 return true;
1776 }
1777 return false;
1778 }
1779
1780 if (cmp(KEY(root), key))
1782 {
1783 ts = root;
1784 return true;
1785 }
1786
1787 return false; // key exists in the tree
1788}
1789
1809template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1810inline bool split_key_rec(Node *&root, const typename Node::key_type &key, Node *&ts, Node *&tg,
1811 const Compare &cmp = Compare()) noexcept
1812{
1814 const bool ret = split_key_rec_helper(root, key, ts, tg, cmp);
1815 if (ret)
1816 root = Node::NullPtr;
1817 return ret;
1818}
1819
1820template <BinNodeLike Node, class Compare>
1821inline void split_key_dup_rec_helper(Node *root, const typename Node::key_type &key,
1822 Node *&ts, Node *&tg, Compare &cmp) noexcept
1823{
1824 if (root == Node::NullPtr)
1825 {
1826 ts = tg = Node::NullPtr;
1827 return;
1828 }
1829
1830 if (cmp(KEY(root), key))
1831 {
1833 ts = root;
1834 }
1835 else
1836 {
1838 tg = root;
1839 }
1840}
1841
1856template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1857inline void split_key_dup_rec(Node *&root, const typename Node::key_type &key, Node *&ts, Node *&tg,
1858 const Compare &cmp = Compare()) noexcept
1859{
1862 root = Node::NullPtr;
1863}
1864
1878template <BinNodeLike Node>
1879inline Node *join_exclusive(Node *&ts, Node *&tg) noexcept
1880{
1881 if (ts == Node::NullPtr)
1882 return tg;
1883
1884 if (tg == Node::NullPtr)
1885 return ts;
1886
1888
1889 RLINK(ts) = tg;
1890 Node *ret_val = ts;
1891 ts = tg = Node::NullPtr; // empty the trees
1892
1893 return ret_val;
1894}
1895
1907template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1908inline Node *remove_from_bst(Node *&root, const typename Node::key_type &key,
1909 const Compare &cmp = Compare()) noexcept
1910{
1912 if (root == Node::NullPtr)
1913 return Node::NullPtr;
1914
1915 if (cmp(key, KEY(root)))
1916 return remove_from_bst(LLINK(root), key, cmp);
1917 if (cmp(KEY(root), key))
1918 return remove_from_bst(RLINK(root), key, cmp);
1919
1920 Node *ret_val = root; // save root that is going to be removed
1922
1923 ret_val->reset();
1924
1925 return ret_val;
1926}
1927
1942template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1943inline Node *insert_root(Node *&root, Node *p, const Compare &cmp = Compare()) noexcept
1944{
1946 Node *l = Node::NullPtr, *r = Node::NullPtr;
1947
1948 if (not split_key_rec(root, KEY(p), l, r, cmp))
1949 return Node::NullPtr;
1950
1951 LLINK(p) = l;
1952 RLINK(p) = r;
1953 root = p;
1954
1955 return root;
1956}
1957
1968template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1969inline Node *insert_dup_root(Node *&root, Node *p, const Compare &cmp = Compare()) noexcept
1970{
1972 split_key_dup_rec(root, KEY(p), LLINK(p), RLINK(p), cmp);
1973 return root = p;
1974}
1975
1989template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
1990inline Node *join_preorder(Node *t1, Node *t2, Node *&dup, const Compare &cmp = Compare()) noexcept
1991{
1992 if (t2 == Node::NullPtr)
1993 return t1;
1994
1995 Node *l = LLINK(t2);
1996 Node *r = RLINK(t2);
1997
1998 t2->reset();
1999
2000 if (insert_in_bst(t1, t2, cmp) == Node::NullPtr)
2001 insert_in_bst(dup, t2, cmp); // insertion has failed
2002
2003 join_preorder(t1, l, dup, cmp);
2004 join_preorder(t1, r, dup, cmp);
2005
2006 return t1;
2007}
2008
2023template <BinNodeLike Node, class Compare = Aleph::less<typename Node::key_type>>
2024inline Node *join(Node *t1, Node *t2, Node *&dup, const Compare &cmp = Compare()) noexcept
2025{
2026 if (t1 == Node::NullPtr)
2027 return t2;
2028
2029 if (t2 == Node::NullPtr)
2030 return t1;
2031
2032 Node *l = LLINK(t1);
2033 Node *r = RLINK(t1);
2034
2035 t1->reset();
2036
2037 while (t1 != Node::NullPtr and insert_root(t2, t1, cmp) == Node::NullPtr)
2038 {
2039 Node *p = remove_from_bst(t1, KEY(t1), cmp);
2040
2041 assert(p != Node::NullPtr);
2042
2043 insert_in_bst(dup, p, cmp);
2044 }
2045
2046 LLINK(t2) = join(l, LLINK(t2), dup, cmp);
2047 RLINK(t2) = join(r, RLINK(t2), dup, cmp);
2048
2049 return t2;
2050}
2051
2057template <BinNodeLike Node>
2058inline Node *rotate_to_right(Node *p) noexcept
2059{
2060 assert(p != Node::NullPtr);
2061
2062 Node *q = LLINK(p);
2063 LLINK(p) = RLINK(q);
2064 RLINK(q) = p;
2065
2066 return q;
2067}
2068
2076template <BinNodeLike Node>
2077inline Node *rotate_to_right(Node *p, Node *pp) noexcept
2078{
2079 assert(p != Node::NullPtr);
2080 assert(pp != Node::NullPtr);
2081 assert(LLINK(pp) == p or RLINK(pp) == p);
2082
2083 Node *q = LLINK(p);
2084 LLINK(p) = RLINK(q);
2085 RLINK(q) = p;
2086
2087 if (LLINK(pp) == p) // update the parent
2088 LLINK(pp) = q;
2089 else
2090 RLINK(pp) = q;
2091
2092 return q;
2093}
2094
2100template <BinNodeLike Node>
2101inline Node *rotate_to_left(Node *p) noexcept
2102{
2103 assert(p != Node::NullPtr);
2104
2105 Node *q = RLINK(p);
2106 RLINK(p) = LLINK(q);
2107 LLINK(q) = p;
2108
2109 return q;
2110}
2111
2118template <BinNodeLike Node>
2119inline Node *rotate_to_left(Node *p, Node *pp) noexcept
2120{
2121 assert(p != Node::NullPtr);
2122 assert(pp != Node::NullPtr);
2123 assert(LLINK(pp) == p or RLINK(pp) == p);
2124
2125 Node *q = RLINK(p);
2126 RLINK(p) = LLINK(q);
2127 LLINK(q) = p;
2128
2129 // update the parent
2130 if (LLINK(pp) == p)
2131 LLINK(pp) = q;
2132 else
2133 RLINK(pp) = q;
2134
2135 return q;
2136}
2137
2152template <BinNodeLike Node, class Key, class Compare = Aleph::less<typename Node::key_type>>
2153inline void split_key(Node *&root, const Key &key, Node *&l, Node *&r,
2154 const Compare &cmp = Compare()) noexcept
2155{
2157 assert(l == Node::NullPtr and r == Node::NullPtr);
2158 if (root == Node::NullPtr)
2159 {
2160 l = r = Node::NullPtr;
2161 return;
2162 }
2163
2164 Node **current_parent = nullptr;
2165 Node **pending_child = nullptr;
2166 bool current_is_right = true;
2167 if (cmp(key, KEY(root)))
2168 {
2169 r = root;
2170 pending_child = &l;
2171 }
2172 else
2173 {
2174 l = root;
2175 pending_child = &r;
2176 current_is_right = false;
2177 }
2178
2179 Node *current = root;
2180 while (current != Node::NullPtr)
2181 {
2182 if (cmp(key, KEY(current)))
2183 { /* current must be in right side */
2185 {
2187 *pending_child = *current_parent; /* change of side */
2189 }
2190 current_parent = &LLINK(current);
2191 }
2192 else
2193 { /* current must be in left side */
2194 if (current_is_right)
2195 {
2197 *pending_child = *current_parent; /* change of side */
2199 }
2200 current_parent = &RLINK(current);
2201 }
2202 current = *current_parent;
2203 }
2204 *pending_child = Node::NullPtr;
2205 root = Node::NullPtr;
2206}
2207
2217template <BinNodeLike Node>
2218inline void swap_node_with_successor(Node *p, // Node for swapping
2219 Node *&pp, // parent of p
2220 Node *q, // Successor inorder of p
2221 Node *&pq) // parent of q
2222 noexcept
2223{
2224 assert(p != Node::NullPtr and q != Node::NullPtr and pp != Node::NullPtr and pq != Node::NullPtr);
2225 assert(LLINK(pp) == p or RLINK(pp) == p);
2226 assert(LLINK(pq) == q or RLINK(pq) == q);
2227 assert(LLINK(q) == Node::NullPtr);
2228
2229 /* Set of pp to its new son q */
2230 if (LLINK(pp) == p)
2231 LLINK(pp) = q;
2232 else
2233 RLINK(pp) = q;
2234
2235 LLINK(q) = LLINK(p);
2236 LLINK(p) = Node::NullPtr;
2237
2238 /* Checks if successor is right child of p. In this case, p will
2239 become q's son. This situation happens when p's son does not have
2240 a left branch */
2241 if (RLINK(p) == q)
2242 {
2243 RLINK(p) = RLINK(q);
2244 RLINK(q) = p;
2245 pq = pp;
2246 pp = q;
2247 return;
2248 }
2249
2250 /* In this case, successor is the leftmost node descending from
2251 right son of p */
2252 Node *qr = RLINK(q);
2253 RLINK(q) = RLINK(p);
2254 LLINK(pq) = p;
2255 RLINK(p) = qr;
2256
2257 std::swap(pp, pq);
2258}
2259
2269template <BinNodeLike Node>
2270inline void swap_node_with_predecessor(Node *p, // Node for swapping
2271 Node *&pp, // p's parent
2272 Node *q, // Predecessor inorder of p
2273 Node *&pq) // q's parent
2274 noexcept
2275{
2276 assert((p != Node::NullPtr) and (q != Node::NullPtr) and (pp != Node::NullPtr) and
2277 (pq != Node::NullPtr));
2278 assert((RLINK(pp) == p) or (LLINK(pp) == p));
2279 assert((RLINK(pq) == q) or (LLINK(pq) == q));
2280 assert(RLINK(q) == Node::NullPtr);
2281
2282 /* Set of pp to its new son q */
2283 if (RLINK(pp) == p)
2284 RLINK(pp) = q;
2285 else
2286 LLINK(pp) = q;
2287
2288 RLINK(q) = RLINK(p);
2289 RLINK(p) = Node::NullPtr;
2290
2291 /* Checks if predecessor is left child of p. In this case, p will
2292 become q's son. This situation happens when p's son does not have
2293 a right branch */
2294 if (LLINK(p) == q)
2295 {
2296 LLINK(p) = LLINK(q);
2297 LLINK(q) = p;
2298 pq = pp;
2299 pp = q;
2300 return;
2301 }
2302
2303 /* In this case, predecessor is the rightmost node descending from
2304 right son of p */
2305 Node *ql = LLINK(q);
2306 LLINK(q) = LLINK(p);
2307 RLINK(pq) = p;
2308 LLINK(p) = ql;
2309 std::swap(pp, pq);
2310}
2311
2325template <BinNodeLike Node, class Key = typename Node::key_type,
2327inline Node *insert_root_rec(Node *root, Node *p, const Compare &cmp = Compare()) noexcept
2328{
2330 if (root == Node::NullPtr)
2331 return p; /* insertion in an empty tree */
2332
2333 if (cmp(KEY(p), KEY(root)))
2334 { /* insert in the left subtree */
2336 if (left_branch == Node::NullPtr)
2337 return Node::NullPtr;
2338
2341 }
2342 else if (cmp(KEY(root), KEY(p)))
2343 { /* insert in the right subtree */
2345 if (right_branch == Node::NullPtr)
2346 return Node::NullPtr;
2347
2350 }
2351 else
2352 return Node::NullPtr; /* duplicated key */
2353
2354 return root;
2355}
2356
2367template <BinNodeLike Node, class Key = typename Node::key_type,
2369inline Node *search_or_insert_root_rec(Node *root, Node *p, const Compare &cmp = Compare()) noexcept
2370{
2372 if (root == Node::NullPtr)
2373 return p; // insertion in empty tree
2374
2375 if (cmp(KEY(p), KEY(root)))
2376 { // insert in left subtree
2378 if (left_branch == p)
2379 {
2382 return p;
2383 }
2384
2385 return left_branch;
2386 }
2387 if (cmp(KEY(root), KEY(p)))
2388 { // insert in right subtree
2390 if (right_branch == p)
2391 {
2394 return p;
2395 }
2396
2397 return right_branch;
2398 }
2399
2400 return root;
2401}
2402
2410template <class Node>
2412{
2413 Node *root = nullptr;
2414 Node *curr = Node::NullPtr;
2416
2417public:
2419 void swap(BinNodePrefixIterator &it) noexcept
2420 {
2421 std::swap(root, it.root);
2422 std::swap(curr, it.curr);
2423 s.swap(it.s);
2424 }
2425
2427
2431 {
2432 // empty
2433 }
2434
2436 {
2437 // empty
2438 }
2439
2441 {
2442 swap(it);
2443 }
2444
2447 {
2448 curr = root;
2449 s.empty();
2450 }
2451
2452private:
2453 // Helper function for finding last node
2454 static Node *last(Node *p) noexcept
2455 {
2456 if (RLINK(p) != Node::NullPtr)
2457 return last(RLINK(p));
2458
2459 if (LLINK(p) != Node::NullPtr)
2460 return last(LLINK(p));
2461
2462 return p;
2463 }
2464
2465public:
2468 {
2469 s.empty();
2470 if (root == Node::NullPtr)
2471 {
2472 curr = Node::NullPtr;
2473 return;
2474 }
2475
2476 curr = last(root);
2477 }
2478
2481 {
2482 curr = Node::NullPtr;
2483 s.empty();
2484 }
2485
2487 {
2488 if (this == &it)
2489 return *this;
2490
2491 root = it.root;
2492 curr = it.curr;
2493 s = it.s;
2494 return *this;
2495 }
2496
2498 {
2499 swap(it);
2500 return *this;
2501 }
2502
2505 {
2506 return curr != Node::NullPtr;
2507 }
2508
2511 {
2512 return curr;
2513 }
2514
2517 {
2518 ah_overflow_error_if(not has_curr()) << "Iterator overflow";
2519 return get_curr_ne();
2520 }
2521
2525 {
2526 auto l = LLINK(curr), r = RLINK(curr);
2527 if (l != Node::NullPtr)
2528 {
2529 curr = l;
2530 if (r != Node::NullPtr)
2531 s.push(r);
2532 return;
2533 }
2534
2535 if (r != Node::NullPtr)
2536 {
2537 curr = r;
2538 return;
2539 }
2540
2541 if (s.is_empty())
2542 curr = Node::NullPtr;
2543 else
2544 curr = s.pop();
2545 }
2546
2548 void next()
2549 {
2550 ah_overflow_error_if(not has_curr()) << "Iterator overflow";
2551 next_ne();
2552 }
2553};
2554
2578template <BinNodeLike Node, class Op>
2580{
2581 for (BinNodePrefixIterator<Node> it(root); it.has_curr(); it.next_ne())
2582 if (not op(it.get_curr()))
2583 return false;
2584 return true;
2585}
2586
2605template <BinNodeLike Node, class Op>
2607{
2608 for (BinNodePrefixIterator<Node> it(root); it.has_curr(); it.next_ne())
2609 op(it.get_curr());
2610}
2611
2619template <class Node>
2621{
2622 mutable Node *root = Node::NullPtr;
2623 Node *curr = Node::NullPtr;
2624 mutable long pos = 0;
2626
2628 {
2629 while (LLINK(r) != Node::NullPtr)
2630 {
2631 s.push(r);
2632 r = LLINK(r);
2633 }
2634 return r;
2635 }
2636
2637 static Node *advance_to_max(Node *r) noexcept
2638 {
2639 while (RLINK(r) != Node::NullPtr)
2640 r = RLINK(r);
2641
2642 return r;
2643 }
2644
2646 {
2647 if (root != Node::NullPtr)
2649 pos = 0;
2650 }
2651
2652public:
2655 {
2656 return curr != Node::NullPtr and LLINK(curr) == Node::NullPtr and s.is_empty();
2657 }
2658
2660 {
2661 return curr != Node::NullPtr and RLINK(curr) == Node::NullPtr and s.is_empty();
2662 }
2663
2664 void swap(BinNodeInfixIterator &it) noexcept
2665 {
2666 std::swap(root, it.root);
2667 std::swap(curr, it.curr);
2668 std::swap(pos, it.pos);
2669 s.swap(it.s);
2670 }
2671
2673
2675 BinNodeInfixIterator(Node *r) noexcept : root(r), s(Node::MaxHeight)
2676 {
2677 init();
2678 }
2679
2681 : root(it.root), curr(it.curr), pos(it.pos), s(it.s)
2682 {
2683 // empty
2684 }
2685
2687 {
2688 swap(it);
2689 }
2690
2693 {
2694 s.empty();
2695 init();
2696 }
2697
2700 {
2701 s.empty();
2702 if (root == Node::NullPtr)
2703 {
2704 curr = Node::NullPtr;
2705 pos = 0;
2706 return;
2707 }
2708
2710 pos = -1; // pending: computed lazily by get_pos()
2711 }
2712
2714 {
2715 s.empty();
2716 curr = Node::NullPtr;
2717 pos = 0;
2718 }
2719
2721 {
2722 if (this == &it)
2723 return *this;
2724
2725 root = it.root;
2726 curr = it.curr;
2727 pos = it.pos;
2728 s = it.s;
2729 return *this;
2730 }
2731
2733 {
2734 swap(it);
2735 return *this;
2736 }
2737
2740 {
2741 return curr != Node::NullPtr;
2742 }
2743
2746 {
2747 return curr;
2748 }
2749
2752 {
2753 ah_overflow_error_if(not has_curr()) << "Iterator overflow";
2754 return curr;
2755 }
2756
2758 size_t get_pos() const
2759 {
2760 if (pos < 0)
2761 pos = static_cast<long>(size(root)) - 1;
2762 return pos;
2763 }
2764
2766 {
2767 if (pos < 0) // resolve the position left pending by reset_last()
2768 pos = static_cast<long>(size(root)) - 1;
2769
2770 ++pos;
2771 curr = RLINK(curr);
2772 if (curr != Node::NullPtr)
2773 {
2775 return;
2776 }
2777
2778 if (s.is_empty())
2779 curr = Node::NullPtr;
2780 else
2781 curr = s.pop();
2782 }
2783
2786 void next()
2787 {
2788 ah_overflow_error_if(not has_curr()) << "Iterator overflow";
2789 next_ne();
2790 }
2791};
2792
2816template <BinNodeLike Node, class Op>
2818{
2819 for (BinNodeInfixIterator<Node> it(root); it.has_curr(); it.next_ne())
2820 if (not op(it.get_curr()))
2821 return false;
2822 return true;
2823}
2824
2829template <BinNodeLike Node, class Op>
2830bool traverse(Node *root, Op op)
2831{
2832 return infix_traverse(root, op);
2833}
2834
2853template <BinNodeLike Node, class Op>
2855{
2856 for (BinNodeInfixIterator<Node> it(root); it.has_curr(); it.next_ne())
2857 op(it.get_curr());
2858}
2859} // namespace Aleph
2860
2861#endif // TPL_BINNODEUTILS_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
Exception handling system with formatted messages for Aleph-w.
#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_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
Standard functor implementations and comparison objects.
WeightedDigraph::Node Node
Space-efficient bit array implementation.
@ KEY
Definition btreepic.C:169
EepicNode< long > * build_tree()
Definition btreepic.C:1435
size_t size_t int32_t * out
Definition ca-c-api.h:120
Stack implemented with simple dynamic array and with bounds verification.
void swap(ArrayStack &s) noexcept
Swap this with s
void empty() noexcept
Empty the stack.
bool is_empty() const noexcept
Return true if stack is empty.
T pop()
Extract the last more recently inserted element.
T & push(const T &data)
Push into stack a copy of data
Inorder iterator on the nodes of a binary tree.
Node * get_curr_ne() const noexcept
Return the current link guaranteeing no exception. Be careful.
void next()
Move the iterator one position forward.
void reset_last() noexcept
Reset the iterator to the last node inorder.
Node * get_curr() const
Return the current node. Throw overflow_error if there is no current.
BinNodeInfixIterator(const BinNodeInfixIterator &it)
bool is_last() const noexcept
bool has_curr() const noexcept
Return true the iterator has current node.
BinNodeInfixIterator(Node *r) noexcept
Initialize an iterator on the first node inorder.
bool is_in_first() const noexcept
Return true if the iterator is on the first node.
BinNodeInfixIterator(BinNodeInfixIterator &&it) noexcept
BinNodeInfixIterator & operator=(const BinNodeInfixIterator &it)
Node * advance_to_min(Node *r) noexcept
static Node * advance_to_max(Node *r) noexcept
size_t get_pos() const
Return the current position of iterator. Only valid if has_curr() == true.
void swap(BinNodeInfixIterator &it) noexcept
void reset_first() noexcept
Reset the iterator to the first node inorder.
Preorder iterator on the nodes of a binary tree.
void next_ne() noexcept
Move the iterator one position forward guaranteeing no exception.
Node * get_curr_ne() const noexcept
Return the current link guaranteeing no exception. Be careful.
bool has_curr() const noexcept
Return true if iterator has current node.
BinNodePrefixIterator(BinNodePrefixIterator &&it) noexcept
Node * get_curr() const
Return a pointer to current node.
void reset_first() noexcept
Reset the iterator to the first node in preorder sense.
void reset_last() noexcept
Reset the iterator to the last node in preorder.
BinNodePrefixIterator(Node *r) noexcept
Initialize an iterator on the first node in preorder for the tree with root r
void next()
Move the iterator one position forward.
void swap(BinNodePrefixIterator &it) noexcept
Swap thiswith it
BinNodePrefixIterator & operator=(const BinNodePrefixIterator &it)
void end() noexcept
Put the iterator in end state.
BinNodePrefixIterator(const BinNodePrefixIterator &it)
static Node * last(Node *p) noexcept
Contiguous array of bits.
Definition bitArray.H:201
int read_bit(const size_t i) const
Read bit i.
Definition bitArray.H:389
void load_from_array_of_chars(const unsigned char str[], const size_t num_bits)
Reads an array of bits saved in a character array.
Definition bitArray.H:699
void load(std::istream &input)
Loads an array of bits from a file.
Definition bitArray.H:602
void push(const unsigned int value)
Inserts the value at the end of the array.
Definition bitArray.H:462
constexpr size_t size() const noexcept
Returns the dimension of the bit array.
Definition bitArray.H:346
Dynamic doubly linked list with O(1) size and bidirectional access.
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.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
Generic inorder traversal of a binary tree.
void traverse(Node *root, Op &&op) const
Invoke to traversal from root node.
static void for_each_inorder(Node *root, Op &&op)
void operator()(Node *root, Op &op) const
Generic postorder traversal of a binary tree.
void operator()(Node *root, Op &op) const
static void postorder(Node *root, Op &&op)
void traverse(Node *root, Op &&op) const
Invoke the traversal.
Generic preorder traversal of a binary tree.
static void preorder(Node *root, Op &&op)
void traverse(Node *root, Op &&op) const
Invoke the traversal.
void operator()(Node *root, Op &op) const
__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
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4129
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
bool prefix_traverse(Node *root, Op op)
Traverse a tree in preorder via its iterator and performs a conditioned operation on each item.
int postOrderRec(Node *root, void(*visitFct)(Node *, int, int))
Traverse recursively in postorder a binary tree.
size_t compute_cardinality_rec(Node *root) noexcept
Count the number of nodes of a binary tree.
Node * rotate_to_left(Node *p) noexcept
Rotate to the left the tree with root p
int preOrderRec(Node *root, void(*visitFct)(Node *, int, int))
Traverse recursively in preorder a binary tree.
void save_tree_in_array_of_chars(Node *root, const std::string &array_name, std::ostream &output)
Generate C++ array declarations for a binary tree.
Node * search_rank_parent(Node *root, const typename Node::key_type &key, const Compare &cmp=Compare()) noexcept
Rank search of a key in a binary search tree.
void save_tree_keys_in_prefix(Node *root, std::ostream &output)
Store in output stream the tree keys in preorder.
void load_tree_keys_in_prefix(Node *root, std::istream &input)
Load the keys stored in preorder from an input stream.
bool level_traverse(Node *root, Operation &operation)
Level traverse a tree and execute an operation.
DynDlist< Node * > compute_nodes_in_level(Node *root, const int &level)
Count the number of nodes in a specific tree level.
Node * join_preorder(Node *t1, Node *t2, Node *&dup, const Compare &cmp=Compare()) noexcept
Union of two binary search trees.
void swap_node_with_successor(Node *p, Node *&pp, Node *q, Node *&pq) noexcept
Swap a node with its successor inorder.
Node * remove_from_bst(Node *&root, const typename Node::key_type &key, const Compare &cmp=Compare()) noexcept
Remove a key from a binary search tree.
void for_each_in_order(Node *root, Op &&op)
Execute an operation in order sense for each node of tree.
Node * find_predecessor(Node *p, Node *&pp) noexcept
Find the inorder predecessor of p
Node * load_tree_from_array(const unsigned char bits[], const size_t &num_bits, const char *keys[])
Build a binary tree from two arrays.
Node * search_parent(Node *root, const typename Node::key_type &key, Node *&parent, const Compare &cmp=Compare()) noexcept
Search a key and find its node and parent.
Node * find_min(Node *root) noexcept
Return the minimum key contained in a binary search tree.
Node * rotate_to_right(Node *p) noexcept
Rotate to the right the tree with root p
bool split_key_rec(Node *&root, const typename Node::key_type &key, Node *&ts, Node *&tg, const Compare &cmp=Compare()) noexcept
Split recursively according to a key.
Node * find_successor(Node *p, Node *&pp) noexcept
Find the inorder successor of p
Node * copyRec(Node *root)
Copy recursively a tree.
void for_each_postorder(Node *root, Op &&op)
Execute an operation in postorder sense for each node of tree.
Node * load_tree(std::istream &input)
Load and build a binary tree from a stream.
void for_each_preorder(Node *root, Op &&op)
Execute an operation in preorder sense for each node of tree.
Node * search_or_insert_in_bst(Node *&r, Node *p, const Compare &cmp=Compare()) noexcept
Search or insert a node in a binary search tree.
void save_tree(Node *root, std::ostream &output)
Store a binary tree in a stream.
void split_key_dup_rec(Node *&root, const typename Node::key_type &key, Node *&ts, Node *&tg, const Compare &cmp=Compare()) noexcept
Split a tree according to a key value.
ThreeWayCmp three_way_compare(const T &a, const T &b, const Compare &cmp=Compare()) noexcept
Three-way comparison using a binary comparator.
bool check_bst(Node *p, const Compare &cmp=Compare())
Return true if p is a binary search tree.
Node * bits_to_tree(const BitArray &array, int idx=0)
Build a binary tree given its bits code.
Node * insert_in_bst(Node *&r, Node *p, const Compare &cmp=Compare()) noexcept
Insert a node p in a binary search tree.
void tree_to_bits(Node *root, BitArray &array)
Compute a bit code for the binary tree.
size_t internal_path_length(Node *p) noexcept
Compute the internal path length.
void preOrderThreaded(Node *node, void(*visitFct)(Node *))
Traverse preorder a binary tree without recursion and without stack.
void inOrderThreaded(Node *root, void(*visitFct)(Node *))
Traverse inorder a binary tree without recursion and without stack.
Node * preorder_to_bst(DynArray< typename Node::key_type > &preorder, int l, int r, const Compare &cmp=Compare())
Build a binary search tree from its preorder traversal.
void levelOrder(Node *root, void(*visitFct)(Node *, int, bool))
Traverse a binary tree by levels.
int inOrderRec(Node *root, void(*visitFct)(Node *, int, int))
Traverse recursively inorder a binary tree.
Node * join_exclusive(Node *&ts, Node *&tg) noexcept
Exclusive join of two binary trees.
void destroyRec(Node *&root) noexcept
Free recursively all the memory occupied by the tree root
Node * searchInBinTree(Node *root, const typename Node::key_type &key, const Compare &cmp=Compare()) noexcept
Search a key in a binary search tree.
Node * search_or_insert_root_rec(Node *root, Node *p, const Compare &cmp=Compare()) noexcept
Search and eventually insert p as root in a binary search tree.
Node * insert_dup_in_bst(Node *&root, Node *p, const Compare &cmp=Compare()) noexcept
Insert a node p in a binary search tree.
Node * insert_root(Node *&root, Node *p, const Compare &cmp=Compare()) noexcept
Insert the node p as root of a binary search tree.
Node * insert_dup_root(Node *&root, Node *p, const Compare &cmp=Compare()) noexcept
Insert node p as root of a binary search tree.
void swap_node_with_predecessor(Node *p, Node *&pp, Node *q, Node *&pq) noexcept
Swap a node with its predecessor inorder.
Node * insert_root_rec(Node *root, Node *p, const Compare &cmp=Compare()) noexcept
Insert a node as root in a binary search tree.
void assert_valid_tree_root(const Node *root) noexcept
Debug-only check that root is a valid tree for Node.
bool infix_traverse(Node *root, Op op)
Traverse a tree in inorder via its iterator and performs a conditioned operation on each item.
size_t computeHeightRec(Node *root) noexcept
Compute recursively the height of root
Node * find_max(Node *root) noexcept
Return the maximum key contained in a binary search tree.
void split_key(Node *&root, const Key &key, Node *&l, Node *&r, const Compare &cmp=Compare()) noexcept
Split a binary search tree according to a key.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t size(Node *root) noexcept
static void infix(Node *root, DynList< Node * > &acc)
bool traverse(Node *root, Op op)
static void suffix(Node *root, DynList< Node * > &acc)
void infix_for_each(Node *root, Op op)
Traverse all the container and performs an operation on each element.
void inorder_rec_helper(Node *node, const int &level, int &position, void(*visitFct)(Node *, int, int))
void load_tree_keys_from_array(Node *root, const char *keys[], int &idx)
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
std::string code(Node *root)
Compute a string with the Lukasiewicz`s word of a tree.
void preorder_rec_helper(Node *p, const int &level, int &position, void(*visitFct)(Node *, int, int))
static void prefix(Node *root, DynList< Node * > &acc)
bool split_key_rec_helper(Node *root, const typename Node::key_type &key, Node *&ts, Node *&tg, Compare &cmp) noexcept
void postorder_rec_helper(Node *node, const int &level, int &position, void(*visitFct)(Node *, int, int))
bool less_or_equal_than(const T &op1, const T &op2, Compare &cmp)
Determines if op1 is less than or equal to op2 using a comparison operator.
Definition ahFunction.H:877
void put_tree_keys_in_array(Node *root, std::ostream &out)
Node< Key > * build_postorder(const DynArray< Key > &post, long lp, long rp, const DynArray< Key > &in, long li, long ri)
ThreeWayCmp
Constants for three-way comparison results.
@ CmpGreater
First argument is greater than second.
@ CmpLess
First argument is less than second.
@ CmpEqual
Arguments are equal.
bool areEquivalents(Node *t1, Node *t2, Equal &op) noexcept
Return true if trees are equivalents.
Node * bits_to_tree_helper(const BitArray &array, int &i)
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
size_t internal_path_length_helper(Node *p, const size_t &level) noexcept
void split_key_dup_rec_helper(Node *root, const typename Node::key_type &key, Node *&ts, Node *&tg, Compare &cmp) noexcept
bool areSimilar(Node *t1, Node *t2) noexcept
Return true if both trees are similar.
bool check_bst_range(Node *p, const typename Node::key_type *min_key, const typename Node::key_type *max_key, const Compare &cmp)
void compute_nodes_in_level_helper(Node *root, long level, const long current_level, DynDlist< Node * > &level_list)
void callKeyDestructorsRec(Node *&root) noexcept
Traverses recursively the tree and calls key's destructors.
void prefix_for_each(Node *root, Op op)
Traverse in preorder all the container and performs an operation on each element.
#define RLINK(i, n)
int keys[]
#define LLINK(i, n)
DynArray< int > preorder
DynArray< int > postorder
DynArray< int > inorder
gsl_rng * r
Circular queue implementations backed by arrays.
Stack implementations backed by dynamic or fixed arrays.
Basic binary tree node definitions.
Dynamic doubly linked list implementation.
Dynamic queue implementation based on linked lists.
DynList< int > l
ofstream output
Definition writeHeap.C:215