Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_binTreeOps.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
31
42# ifndef TPL_BINTREEOPS_H
43# define TPL_BINTREEOPS_H
44
45# include <tpl_binNodeUtils.H>
46# include <tpl_binNodeXt.H>
47# include <ah-concepts.H>
48
49namespace Aleph
50{
56 template <class Node, class Cmp = Aleph::less<typename Node::key_type>>
59 {
60 protected:
62
63 public:
65 Cmp &key_comp() noexcept { return cmp; }
66
68 Cmp &get_compare() noexcept { return cmp; }
69
70 using Key = typename Node::key_type;
71
72 using key_type = typename Node::key_type;
73
76 { /* empty */
77 }
78
86 [[nodiscard]] Node * search(Node *root, const Key & key) noexcept
87 {
88 return searchInBinTree(root, key, cmp);
89 }
90
100 [[nodiscard]] Node * search_parent(Node *root, const Key & key, Node *& parent) noexcept
101 {
102 return Aleph::search_parent<Node, Cmp>(root, key, parent, cmp);
103 }
104
122 [[nodiscard]] Node * search_rank_parent(Node *root, const Key & key) noexcept
123 {
125 }
126
137 [[nodiscard]] Node * insert(Node *& root, Node *p) noexcept
138 {
139 if (root == Node::NullPtr)
140 return root = p;
141
142 if (cmp(KEY(p), KEY(root))) // p < root
143 {
144 if (LLINK(root) != Node::NullPtr) [[likely]]
146 return insert(LLINK(root), p);
147 }
148 if (cmp(KEY(root), KEY(p))) // p > root
149 {
150 if (RLINK(root) != Node::NullPtr) [[likely]]
152 return insert(RLINK(root), p);
153 }
154
155 return Node::NullPtr; // Repeated key ==> no insertion
156 }
157
168 Node * insert_dup(Node *& root, Node *p) noexcept
169 {
170 if (root == Node::NullPtr)
171 return root = p;
172
173 if (cmp(KEY(p), KEY(root))) // p < root
174 {
175 if (LLINK(root) != Node::NullPtr) [[likely]]
177 return insert_dup(LLINK(root), p);
178 }
179
180 if (RLINK(root) != Node::NullPtr) [[likely]]
182 return insert_dup(RLINK(root), p);
183 }
184
196 Node * search_or_insert(Node *& r, Node *p) noexcept
197 {
198 if (r == Node::NullPtr)
199 return r = p;
200
201 if (cmp(KEY(p), KEY(r))) // p < root
202 {
203 if (LLINK(r) != Node::NullPtr) [[likely]]
205 return search_or_insert(LLINK(r), p);
206 }
207 if (cmp(KEY(r), KEY(p))) // p > root
208 {
209 if (RLINK(r) != Node::NullPtr) [[likely]]
211 return search_or_insert(RLINK(r), p);
212 }
213
214 return r; // key found
215 }
216
217 private:
218 bool split_key_rec_helper(Node *root, const Key & key, Node *& ts, Node *& tg)
219 noexcept
220 {
221 if (root == Node::NullPtr)
222 {
223 ts = tg = Node::NullPtr;
224 return true;
225 }
226
227 if (cmp(key, KEY(root))) // ¿key < KEY(root)?
228 {
230 {
231 tg = root;
232 return true;
233 }
234 return false;
235 }
236
237 if (cmp(KEY(root), key)) // ¿key > KEY(root)?
239 {
240 ts = root;
241 return true;
242 }
243
244 return false;
245 }
246
247 public:
263 bool split_key_rec(Node *& root, const Key & key, Node *& ts, Node *& tg)
264 noexcept
265 {
266 const bool ret = split_key_rec_helper(root, key, ts, tg);
267 if (ret)
268 root = Node::NullPtr;
269 return ret;
270 }
271
272 private:
273 void split_key_dup_rec_helper(Node *root, const typename Node::key_type & key,
274 Node *& ts, Node *& tg) noexcept
275 {
276 if (root == Node::NullPtr)
277 { // Key is not in tree ==> split will succeed
278 ts = tg = Node::NullPtr;
279 return;
280 }
281
282 if (cmp(key, KEY(root))) // ¿key < KEY(root)?
284 else if (cmp(KEY(root), key)) // ¿key > KEY(root)?
286 else // key == KEY(root)
288 }
289
290 public:
302 void split_key_dup_rec(Node *& root, const typename Node::key_type & key,
303 Node *& ts, Node *& tg) noexcept
304 {
306 root = Node::NullPtr;
307 }
308
316 [[nodiscard]] Node * remove(Node *& root, const Key & key) noexcept
317 {
318 if (root == Node::NullPtr)
319 return Node::NullPtr;
320
321 if (cmp(key, KEY(root))) // ¿key < KEY(root)?
322 return remove(LLINK(root), key);
323 if (cmp(KEY(root), key)) // ¿key > KEY(root)?
324 return remove(RLINK(root), key);
325
326 Node *ret_val = root;
328
329 ret_val->reset();
330
331 return ret_val;
332 }
333
345 Node * insert_root(Node *& root, Node *p) noexcept
346 {
347 Node *l = Node::NullPtr, *r = Node::NullPtr;
348
349 if (not split_key_rec(root, KEY(p), l, r))
350 return Node::NullPtr;
351
352 LLINK(p) = l;
353 RLINK(p) = r;
354 root = p;
355
356 return root;
357 }
358
366 Node * insert_dup_root(Node *& root, Node *p) noexcept
367 {
368 split_key_dup_rec(root, KEY(p), LLINK(p), RLINK(p));
369
370 return root = p;
371 }
372
383 [[nodiscard]] Node * join_preorder(Node *t1, Node *t2, Node *& dup) noexcept
384 {
385 if (t2 == Node::NullPtr)
386 return t1;
387
388 Node *l = LLINK(t2);
389 Node *r = RLINK(t2);
390
391 if (insert(t1, t2) == Node::NullPtr)
392 insert(dup, t2);
393
394 join_preorder(t1, l, dup);
395 join_preorder(t1, r, dup);
396
397 return t1;
398 }
399
411 [[nodiscard]] Node * join(Node *t1, Node *t2, Node *& dup) noexcept
412 {
413 if (t1 == Node::NullPtr)
414 return t2;
415
416 if (t2 == Node::NullPtr)
417 return t1;
418
419 Node *l = LLINK(t1);
420 Node *r = RLINK(t1);
421
422 t1->reset();
423
424 while (insert_root(t2, t1) == Node::NullPtr)
425 {
426 Node *p = remove(t1, KEY(t1));
427
428 assert(p != Node::NullPtr);
429
430 insert(dup, p); // Insert the removed node, not t1
431 }
432
433 LLINK(t2) = join(l, LLINK(t2), dup);
434 RLINK(t2) = join(r, RLINK(t2), dup);
435
436 return t2;
437 }
438
450 void split_key(Node *root, const Key & key, Node *& l, Node *& r) noexcept
451 {
452 if (root == Node::NullPtr)
453 {
454 l = r = Node::NullPtr;
455 return;
456 }
457
458 Node **current_parent = nullptr;
459 Node **pending_child = nullptr;
460 bool current_is_right;
461 if (cmp(key, KEY(root)))
462 {
463 r = root;
464 pending_child = &l;
465 current_is_right = true;
466 }
467 else
468 {
469 l = root;
470 pending_child = &r;
471 current_is_right = false;
472 }
473
474 Node *current = root;
475 while (current != Node::NullPtr)
476 {
477 if (cmp(key, KEY(current)))
478 { /* current must be in right side */
480 {
482 *pending_child = *current_parent; /* change of side */
484 }
485
486 current_parent = &LLINK(current);
487 }
488 else
489 { /* current must be in left side */
491 {
493 *pending_child = *current_parent; /* change of side */
495 }
496 current_parent = &RLINK(current);
497 }
498
499 current = *current_parent;
500 }
501
502 *pending_child = Node::NullPtr;
503 root = Node::NullPtr;
504 }
505
517 {
518 if (root == Node::NullPtr)
519 return p; /* insertion in an empty tree */
520
521 if (cmp(KEY(p), KEY(root)))
522 { /* insert in the left subtree */
524 if (left_branch == Node::NullPtr)
525 return Node::NullPtr;
526
529 }
530 else if (cmp(KEY(root), KEY(p)))
531 { /* insert in the right subtree */
533 if (right_branch == Node::NullPtr)
534 return Node::NullPtr;
535
538 }
539 else
540 return Node::NullPtr; /* duplicated key */
541
542 return root;
543 }
544
553 {
554 if (root == Node::NullPtr)
555 return p; // insertion in an empty tree
556
557 if (cmp(KEY(p), KEY(root)))
558 { // insert in the left subtree
560 if (left_branch == p) // Was there insertion?
561 {
564
565 return p;
566 }
567
568 return left_branch; // no la hubo
569 }
570 if (cmp(KEY(root), KEY(p)))
571 { // insert in the right subtree
573 if (right_branch == p) //Was there insertion?
574 {
577
578 return p;
579 }
580
581 return right_branch; // no la hubo
582 }
583
584 return root;
585 }
586 };
587
588
594 template <class Node,
596 class BinTreeXt_Operation : public BinTree_Operation<Node, Cmp>
597 {
598 public:
599 using Key = typename Node::key_type;
600
604 {
605 // empty
606 }
607
618 long inorder_position(Node *r, const Key & key, Node *& p) noexcept
619 {
620 assert(COUNT(Node::NullPtr) == 0);
621
622 if (r == Node::NullPtr)
623 return -1;
624
625 if (this->cmp(key, KEY(r)))
626 {
627 if (LLINK(r) != Node::NullPtr) [[likely]]
629 return inorder_position(LLINK(r), key, p);
630 }
631 if (this->cmp(KEY(r), key))
632 {
633 if (RLINK(r) != Node::NullPtr) [[likely]]
635 long ret = inorder_position(RLINK(r), key, p);
636 if (ret != -1)
637 return ret + COUNT(LLINK(r)) + 1;
638 return ret;
639 }
640 p = r;
641 return COUNT(LLINK(r));
642 }
643
667 long find_position(Node *r, const Key & key, Node *& p) noexcept
668 {
669 assert(COUNT(Node::NullPtr) == 0);
670
671 Node *parent = nullptr;
672 long pos = COUNT(LLINK(r));
673
674 while (r != Node::NullPtr)
675 if (const auto & kr = KEY(r); this->cmp(key, kr)) // key < KEY(r): go left
676 {
677 Node *next = LLINK(r);
679
680 parent = r;
681 r = next;
682
683 // After moving left: new position is COUNT(LLINK(new_r))
684 // which equals old_pos - COUNT(RLINK(new_r)) - 1
685 pos -= (COUNT(RLINK(r)) + 1);
686 }
687 else if (this->cmp(kr, key)) // KEY(r) < key: go right
688 {
689 Node *next = RLINK(r);
691
692 parent = r;
693 r = next;
694
695 // After moving right: add parent + parent's left subtree
696 pos += (COUNT(LLINK(r)) + 1);
697 }
698 else
699 {
700 p = r;
701 return pos;
702 }
703
704 p = parent;
705 return pos;
706 }
707
708
721 bool split_key_rec(Node *root, const Key & key, Node *& l, Node *& r)
722 noexcept
723 {
724 if (root == Node::NullPtr)
725 {
726 l = r = Node::NullPtr;
727 return true;
728 }
729
730 if (this->cmp(key, KEY(root)))
731 {
732 if (not split_key_rec(LLINK(root), key, l, LLINK(root)))
733 return false;
734
735 r = root;
736 COUNT(r) -= COUNT(l);
737 }
738 else if (this->cmp(KEY(root), key))
739 {
740 if (not split_key_rec(RLINK(root), key, RLINK(root), r))
741 return false;
742
743 l = root;
744 COUNT(l) -= COUNT(r);
745 }
746 else
747 return false; // Duplicate Key
748
749 return true;
750 }
751
763 void split_key_dup_rec(Node *root, const Key & key, Node *& l, Node *& r)
764 noexcept
765 {
766 if (root == Node::NullPtr)
767 {
768 l = r = Node::NullPtr;
769 return;
770 }
771
772 if (this->cmp(key, KEY(root)))
773 {
775 r = root;
776 COUNT(r) -= COUNT(l);
777 }
778 else
779 {
781 l = root;
782 COUNT(l) -= COUNT(r);
783 }
784 }
785
800 Node * insert_root(Node *& root, Node *p) noexcept
801 {
802 if (root == Node::NullPtr)
803 return p;
804
805 if (not split_key_rec(root, KEY(p), LLINK(p), RLINK(p)))
806 return Node::NullPtr;
807
808 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
809 root = p;
810
811 return p;
812 }
813
825 Node * insert_dup_root(Node *& root, Node *p) noexcept
826 {
827 if (root == Node::NullPtr)
828 return p;
829
830 split_key_dup_rec(root, KEY(p), LLINK(p), RLINK(p));
831
832 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
833
834 return root = p;
835 }
836 };
837} // end namespace Aleph
838
839# endif // TPL_BINTREEOPS_H
C++20 concepts for constraining comparison functors.
WeightedDigraph::Node Node
@ KEY
Definition btreepic.C:169
Functor encompassing basic operation for extended binary search trees.
BinTreeXt_Operation(Cmp cmp=Cmp()) noexcept
Initialize the functor with comparison criteria cmp
long find_position(Node *r, const Key &key, Node *&p) noexcept
Find the inorder position of a key in an extended binary search tree.
Node * insert_dup_root(Node *&root, Node *p) noexcept
Insert a node as root of an extended binary search tree.
bool split_key_rec(Node *root, const Key &key, Node *&l, Node *&r) noexcept
Split an extended binary search tree according to a key.
typename Node::key_type Key
void split_key_dup_rec(Node *root, const Key &key, Node *&l, Node *&r) noexcept
Split an extended binary search tree according to a key which can be in the tree.
Functor encompassing basic operation for binary search trees.
typename Node::key_type key_type
The type of key.
bool split_key_rec(Node *&root, const Key &key, Node *&ts, Node *&tg) noexcept
Split recursively according to a key.
void split_key_dup_rec_helper(Node *root, const typename Node::key_type &key, Node *&ts, Node *&tg) noexcept
void split_key(Node *root, const Key &key, Node *&l, Node *&r) noexcept
Split a binary search tree according to a key.
Node * join(Node *t1, Node *t2, Node *&dup) noexcept
Fast union of two binary search trees.
Node * search_or_insert(Node *&r, Node *p) noexcept
Search or insert a node in a binary search tree.
Node * insert_dup(Node *&root, Node *p) noexcept
Insert a node p in a binary search tree.
Node * search_parent(Node *root, const Key &key, Node *&parent) noexcept
Search a key and find its node and parent.
typename Node::key_type Key
BinTree_Operation(Cmp cmp_=Cmp()) noexcept
The type of key.
Node * insert_root_rec(Node *root, Node *p) noexcept
Insert a node as root in a binary search tree.
void split_key_dup_rec(Node *&root, const typename Node::key_type &key, Node *&ts, Node *&tg) noexcept
Split a tree according to a key value.
Node * insert_dup_root(Node *&root, Node *p) noexcept
Insert node p as root of a binary search tree.
Node * join_preorder(Node *t1, Node *t2, Node *&dup) noexcept
Union of two binary search trees.
Cmp & get_compare() noexcept
Node * insert_root(Node *&root, Node *p) noexcept
Insert the node p as the root of a binary search tree.
Node * search(Node *root, const Key &key) noexcept
Search a node with a specific key.
Node * search_or_insert_root_rec(Node *root, Node *p) noexcept
Search and eventually insert p as root in a binary search tree.
Cmp & key_comp() noexcept
Return the comparison criteria.
bool split_key_rec_helper(Node *root, const Key &key, Node *&ts, Node *&tg) noexcept
Node * remove(Node *&root, const Key &key) noexcept
Remove a key from a binary search tree.
Node * insert(Node *&root, Node *p) noexcept
Insert a node p in a binary search tree.
__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:4060
Node * rotate_to_left(Node *p) noexcept
Rotate to the left the tree with root p
Node * rotate_to_right(Node *p) noexcept
Rotate to the right the tree with root p
Node * insert_root(Node *&root, Node *p) noexcept
Insert a node p as root of an extended binary search tree.
auto & COUNT(Node *p) noexcept
Return the number of nodes of the tree fron p is root.
Node * join_exclusive(Node *&ts, Node *&tg) noexcept
Exclusive join of two binary trees.
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_rank_parent(Node *root, const Key &key) noexcept
Rank search of a key in a binary search tree.
long inorder_position(Node *r, const Key &key, Node *&p) noexcept
Compute the inorder position of a key.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
#define RLINK(i, n)
#define LLINK(i, n)
gsl_rng * r
Utility functions for binary tree operations.
Extended binary node with subtree count.
DynList< int > l