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
48namespace Aleph
49{
55 template <class Node, class Cmp = Aleph::less<typename Node::key_type>>
57 {
58 protected:
59 Cmp cmp;
60
61 public:
63 Cmp &key_comp() noexcept { return cmp; }
64
66 Cmp &get_compare() noexcept { return cmp; }
67
68 using Key = typename Node::key_type;
69
70 using key_type = typename Node::key_type;
71
74 { /* empty */
75 }
76
84 [[nodiscard]] Node * search(Node *root, const Key & key) noexcept
85 {
86 return searchInBinTree(root, key, cmp);
87 }
88
98 [[nodiscard]] Node * search_parent(Node *root, const Key & key, Node *& parent) noexcept
99 {
100 return Aleph::search_parent<Node, Cmp>(root, key, parent, cmp);
101 }
102
120 [[nodiscard]] Node * search_rank_parent(Node *root, const Key & key) noexcept
121 {
123 }
124
135 [[nodiscard]] Node * insert(Node *& root, Node *p) noexcept
136 {
137 if (root == Node::NullPtr)
138 return root = p;
139
140 if (cmp(KEY(p), KEY(root))) // p < root
141 {
142 if (LLINK(root) != Node::NullPtr) [[likely]]
144 return insert(LLINK(root), p);
145 }
146 if (cmp(KEY(root), KEY(p))) // p > root
147 {
148 if (RLINK(root) != Node::NullPtr) [[likely]]
150 return insert(RLINK(root), p);
151 }
152
153 return Node::NullPtr; // Repeated key ==> no insertion
154 }
155
166 Node * insert_dup(Node *& root, Node *p) noexcept
167 {
168 if (root == Node::NullPtr)
169 return root = p;
170
171 if (cmp(KEY(p), KEY(root))) // p < root
172 {
173 if (LLINK(root) != Node::NullPtr) [[likely]]
175 return insert_dup(LLINK(root), p);
176 }
177
178 if (RLINK(root) != Node::NullPtr) [[likely]]
180 return insert_dup(RLINK(root), p);
181 }
182
194 Node * search_or_insert(Node *& r, Node *p) noexcept
195 {
196 if (r == Node::NullPtr)
197 return r = p;
198
199 if (cmp(KEY(p), KEY(r))) // p < root
200 {
201 if (LLINK(r) != Node::NullPtr) [[likely]]
203 return search_or_insert(LLINK(r), p);
204 }
205 if (cmp(KEY(r), KEY(p))) // p > root
206 {
207 if (RLINK(r) != Node::NullPtr) [[likely]]
209 return search_or_insert(RLINK(r), p);
210 }
211
212 return r; // key found
213 }
214
215 private:
216 bool split_key_rec_helper(Node *root, const Key & key, Node *& ts, Node *& tg)
217 noexcept
218 {
219 if (root == Node::NullPtr)
220 {
221 ts = tg = Node::NullPtr;
222 return true;
223 }
224
225 if (cmp(key, KEY(root))) // ¿key < KEY(root)?
226 {
228 {
229 tg = root;
230 return true;
231 }
232 return false;
233 }
234
235 if (cmp(KEY(root), key)) // ¿key > KEY(root)?
237 {
238 ts = root;
239 return true;
240 }
241
242 return false;
243 }
244
245 public:
261 bool split_key_rec(Node *& root, const Key & key, Node *& ts, Node *& tg)
262 noexcept
263 {
264 const bool ret = split_key_rec_helper(root, key, ts, tg);
265 if (ret)
266 root = Node::NullPtr;
267 return ret;
268 }
269
270 private:
271 void split_key_dup_rec_helper(Node *root, const typename Node::key_type & key,
272 Node *& ts, Node *& tg) noexcept
273 {
274 if (root == Node::NullPtr)
275 { // Key is not in tree ==> split will succeed
276 ts = tg = Node::NullPtr;
277 return;
278 }
279
280 if (cmp(key, KEY(root))) // ¿key < KEY(root)?
282 else if (cmp(KEY(root), key)) // ¿key > KEY(root)?
284 else // key == KEY(root)
286 }
287
288 public:
300 void split_key_dup_rec(Node *& root, const typename Node::key_type & key,
301 Node *& ts, Node *& tg) noexcept
302 {
304 root = Node::NullPtr;
305 }
306
314 [[nodiscard]] Node * remove(Node *& root, const Key & key) noexcept
315 {
316 if (root == Node::NullPtr)
317 return Node::NullPtr;
318
319 if (cmp(key, KEY(root))) // ¿key < KEY(root)?
320 return remove(LLINK(root), key);
321 if (cmp(KEY(root), key)) // ¿key > KEY(root)?
322 return remove(RLINK(root), key);
323
324 Node *ret_val = root;
326
327 ret_val->reset();
328
329 return ret_val;
330 }
331
343 Node * insert_root(Node *& root, Node *p) noexcept
344 {
345 Node *l = Node::NullPtr, *r = Node::NullPtr;
346
347 if (not split_key_rec(root, KEY(p), l, r))
348 return Node::NullPtr;
349
350 LLINK(p) = l;
351 RLINK(p) = r;
352 root = p;
353
354 return root;
355 }
356
364 Node * insert_dup_root(Node *& root, Node *p) noexcept
365 {
366 split_key_dup_rec(root, KEY(p), LLINK(p), RLINK(p));
367
368 return root = p;
369 }
370
381 [[nodiscard]] Node * join_preorder(Node *t1, Node *t2, Node *& dup) noexcept
382 {
383 if (t2 == Node::NullPtr)
384 return t1;
385
386 Node *l = LLINK(t2);
387 Node *r = RLINK(t2);
388
389 if (insert(t1, t2) == Node::NullPtr)
390 insert(dup, t2);
391
392 join_preorder(t1, l, dup);
393 join_preorder(t1, r, dup);
394
395 return t1;
396 }
397
409 [[nodiscard]] Node * join(Node *t1, Node *t2, Node *& dup) noexcept
410 {
411 if (t1 == Node::NullPtr)
412 return t2;
413
414 if (t2 == Node::NullPtr)
415 return t1;
416
417 Node *l = LLINK(t1);
418 Node *r = RLINK(t1);
419
420 t1->reset();
421
422 while (insert_root(t2, t1) == Node::NullPtr)
423 {
424 Node *p = remove(t1, KEY(t1));
425
426 assert(p != Node::NullPtr);
427
428 insert(dup, p); // Insert the removed node, not t1
429 }
430
431 LLINK(t2) = join(l, LLINK(t2), dup);
432 RLINK(t2) = join(r, RLINK(t2), dup);
433
434 return t2;
435 }
436
448 void split_key(Node *root, const Key & key, Node *& l, Node *& r) noexcept
449 {
450 if (root == Node::NullPtr)
451 {
452 l = r = Node::NullPtr;
453 return;
454 }
455
456 Node **current_parent = nullptr;
457 Node **pending_child = nullptr;
458 bool current_is_right;
459 if (cmp(key, KEY(root)))
460 {
461 r = root;
462 pending_child = &l;
463 current_is_right = true;
464 }
465 else
466 {
467 l = root;
468 pending_child = &r;
469 current_is_right = false;
470 }
471
472 Node *current = root;
473 while (current != Node::NullPtr)
474 {
475 if (cmp(key, KEY(current)))
476 { /* current must be in right side */
478 {
480 *pending_child = *current_parent; /* change of side */
482 }
483
484 current_parent = &LLINK(current);
485 }
486 else
487 { /* current must be in left side */
489 {
491 *pending_child = *current_parent; /* change of side */
493 }
494 current_parent = &RLINK(current);
495 }
496
497 current = *current_parent;
498 }
499
500 *pending_child = Node::NullPtr;
501 root = Node::NullPtr;
502 }
503
515 {
516 if (root == Node::NullPtr)
517 return p; /* insertion in an empty tree */
518
519 if (cmp(KEY(p), KEY(root)))
520 { /* insert in the left subtree */
522 if (left_branch == Node::NullPtr)
523 return Node::NullPtr;
524
527 }
528 else if (cmp(KEY(root), KEY(p)))
529 { /* insert in the right subtree */
531 if (right_branch == Node::NullPtr)
532 return Node::NullPtr;
533
536 }
537 else
538 return Node::NullPtr; /* duplicated key */
539
540 return root;
541 }
542
551 {
552 if (root == Node::NullPtr)
553 return p; // insertion in an empty tree
554
555 if (cmp(KEY(p), KEY(root)))
556 { // insert in the left subtree
558 if (left_branch == p) // Was there insertion?
559 {
562
563 return p;
564 }
565
566 return left_branch; // no la hubo
567 }
568 if (cmp(KEY(root), KEY(p)))
569 { // insert in the right subtree
571 if (right_branch == p) //Was there insertion?
572 {
575
576 return p;
577 }
578
579 return right_branch; // no la hubo
580 }
581
582 return root;
583 }
584 };
585
586
592 template <class Node,
594 class BinTreeXt_Operation : public BinTree_Operation<Node, Cmp>
595 {
596 public:
597 using Key = typename Node::key_type;
598
601 : BinTree_Operation<Node, Cmp>(cmp)
602 {
603 // empty
604 }
605
616 long inorder_position(Node *r, const Key & key, Node *& p) noexcept
617 {
618 assert(COUNT(Node::NullPtr) == 0);
619
620 if (r == Node::NullPtr)
621 return -1;
622
623 if (this->cmp(key, KEY(r)))
624 {
625 if (LLINK(r) != Node::NullPtr) [[likely]]
627 return inorder_position(LLINK(r), key, p);
628 }
629 if (this->cmp(KEY(r), key))
630 {
631 if (RLINK(r) != Node::NullPtr) [[likely]]
633 long ret = inorder_position(RLINK(r), key, p);
634 if (ret != -1)
635 return ret + COUNT(LLINK(r)) + 1;
636 return ret;
637 }
638 p = r;
639 return COUNT(LLINK(r));
640 }
641
665 long find_position(Node *r, const Key & key, Node *& p) noexcept
666 {
667 assert(COUNT(Node::NullPtr) == 0);
668
669 Node *parent = nullptr;
670 long pos = COUNT(LLINK(r));
671
672 while (r != Node::NullPtr)
673 if (const auto & kr = KEY(r); this->cmp(key, kr)) // key < KEY(r): go left
674 {
675 Node *next = LLINK(r);
677
678 parent = r;
679 r = next;
680
681 // After moving left: new position is COUNT(LLINK(new_r))
682 // which equals old_pos - COUNT(RLINK(new_r)) - 1
683 pos -= (COUNT(RLINK(r)) + 1);
684 }
685 else if (this->cmp(kr, key)) // KEY(r) < key: go right
686 {
687 Node *next = RLINK(r);
689
690 parent = r;
691 r = next;
692
693 // After moving right: add parent + parent's left subtree
694 pos += (COUNT(LLINK(r)) + 1);
695 }
696 else
697 {
698 p = r;
699 return pos;
700 }
701
702 p = parent;
703 return pos;
704 }
705
706
719 bool split_key_rec(Node *root, const Key & key, Node *& l, Node *& r)
720 noexcept
721 {
722 if (root == Node::NullPtr)
723 {
724 l = r = Node::NullPtr;
725 return true;
726 }
727
728 if (this->cmp(key, KEY(root)))
729 {
730 if (not split_key_rec(LLINK(root), key, l, LLINK(root)))
731 return false;
732
733 r = root;
734 COUNT(r) -= COUNT(l);
735 }
736 else if (this->cmp(KEY(root), key))
737 {
738 if (not split_key_rec(RLINK(root), key, RLINK(root), r))
739 return false;
740
741 l = root;
742 COUNT(l) -= COUNT(r);
743 }
744 else
745 return false; // Duplicate Key
746
747 return true;
748 }
749
761 void split_key_dup_rec(Node *root, const Key & key, Node *& l, Node *& r)
762 noexcept
763 {
764 if (root == Node::NullPtr)
765 {
766 l = r = Node::NullPtr;
767 return;
768 }
769
770 if (this->cmp(key, KEY(root)))
771 {
773 r = root;
774 COUNT(r) -= COUNT(l);
775 }
776 else
777 {
779 l = root;
780 COUNT(l) -= COUNT(r);
781 }
782 }
783
798 Node * insert_root(Node *& root, Node *p) noexcept
799 {
800 if (root == Node::NullPtr)
801 return p;
802
803 if (not split_key_rec(root, KEY(p), LLINK(p), RLINK(p)))
804 return Node::NullPtr;
805
806 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
807 root = p;
808
809 return p;
810 }
811
823 Node * insert_dup_root(Node *& root, Node *p) noexcept
824 {
825 if (root == Node::NullPtr)
826 return p;
827
828 split_key_dup_rec(root, KEY(p), LLINK(p), RLINK(p));
829
830 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
831
832 return root = p;
833 }
834 };
835} // end namespace Aleph
836
837# endif // TPL_BINTREEOPS_H
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.
void reset() noexcept
Definition htlist.H:516
__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
constexpr Node *& RLINK(Node *p) noexcept
Return the right tree of 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.
constexpr Node *& LLINK(Node *p) noexcept
Return a pointer to left subtree.
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
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
DynList< T > maps(const C &c, Op op)
Classic map operation.
Utility functions for binary tree operations.
Extended binary node with subtree count.
DynList< int > l