Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_avlRk.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
32
50# ifndef TPL_AVLRK_H
51# define TPL_AVLRK_H
52
53# include <algorithm>
54# include <ahFunction.H>
55# include <tpl_arrayStack.H>
56# include <tpl_binNodeXt.H>
57# include <tpl_binTreeOps.H>
58# include <tpl_binNodeUtils.H>
59# include <avlNodeRk.H>
60# include <ah-errors.H>
61
62using namespace Aleph;
63
64namespace Aleph
65{
109 template <template <typename> class NodeType, typename Key, class Compare>
111 {
112 public:
114
115 private:
120 Compare cmp;
121
123
125
126 Node * search_and_stack_avl(const Key & key,
127 signed char & cmp_result) noexcept
128 {
130
131 Node *p = root;
132 Node *candidate = nullptr; // Tracks potential duplicate when going right
133 size_t candidate_pos = 0; // Stack size when candidate was set
134
135 do
136 {
137 avl_stack.push(p);
138 if (cmp(key, KEY(p))) // key < KEY(p)
139 {
141 p = LLINK(p);
142 // Prefetch only the child we'll visit next iteration
143 if (p != Node::NullPtr) [[likely]]
145 }
146 else // key >= KEY(p), could be equal
147 {
148 candidate = p;
151 p = RLINK(p);
152 // Prefetch only the child we'll visit next iteration
153 if (p != Node::NullPtr) [[likely]]
155 }
156 }
157 while (p != Node::NullPtr);
158
159 // Optimistic duplicate check: when going right, key >= KEY(candidate)
160 // If also KEY(candidate) >= key (i.e., not less), then key == KEY(candidate)
161 if (candidate != nullptr and not cmp(KEY(candidate), key)) [[unlikely]]
162 {
164 // Truncate stack: remove nodes pushed after candidate
166 return candidate;
167 }
168
169 return avl_stack.top();
170 }
171
173 signed char & cmp_result) noexcept
174 {
177
178 Node *p = root;
179 do
180 {
181 avl_stack.push(p);
182 if (cmp(key, KEY(p))) // key < KEY(p)?
183 {
185 p = LLINK(p);
186 // Prefetch only the child we'll visit next iteration
187 if (p != Node::NullPtr) [[likely]]
189 }
190 else // key >= KEY(p)
191 {
193 p = RLINK(p);
194 // Prefetch only the child we'll visit next iteration
195 if (p != Node::NullPtr) [[likely]]
197 }
198 }
199 while (p != Node::NullPtr);
200
201 return avl_stack.top();
202 }
203
204 // Rotate to left with counter update
205 [[gnu::always_inline]] static Node * rotateLeft(Node *p) noexcept
206 {
207 assert(DIFF(p) == 2);
208 assert(RLINK(p) != Node::NullPtr);
209
210 Node *q = RLINK(p);
211 RLINK(p) = LLINK(q);
212 LLINK(q) = p;
213
214 // Update counters
215 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
216 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
217
218 if (DIFF(q) == 0)
219 {
220 DIFF(q) = -1;
221 DIFF(p) = 1;
222 }
223 else
224 DIFF(q) = DIFF(p) = 0;
225
226 return q;
227 }
228
229 // Rotate to right with counter update
230 [[gnu::always_inline]] static Node * rotateRight(Node *p) noexcept
231 {
232 assert(DIFF(p) == -2);
233 assert(LLINK(p) != Node::NullPtr);
234
235 Node *q = LLINK(p);
236 LLINK(p) = RLINK(q);
237 RLINK(q) = p;
238
239 // Update counters
240 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
241 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
242
243 if (DIFF(q) == 0)
244 {
245 DIFF(q) = 1;
246 DIFF(p) = -1;
247 }
248 else
249 DIFF(q) = DIFF(p) = 0;
250
251 return q;
252 }
253
254 // Double rotate left with counter update
255 [[gnu::always_inline]] static Node * doubleRotateLeft(Node *p) noexcept
256 {
257 assert(DIFF(p) == 2 or DIFF(p) == -2);
258 assert(RLINK(p) != Node::NullPtr and LLINK(RLINK(p)) != Node::NullPtr);
259
260 Node *q = RLINK(p);
261 Node *r = LLINK(q);
262 RLINK(p) = LLINK(r);
263 LLINK(q) = RLINK(r);
264 LLINK(r) = p;
265 RLINK(r) = q;
266
267 // Update counters
268 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
269 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
270 COUNT(r) = COUNT(LLINK(r)) + COUNT(RLINK(r)) + 1;
271
272 unsigned char b, c;
273 if (DIFF(r) == 1)
274 {
275 c = 1;
276 b = 0;
277 }
278 else if (DIFF(r) == -1)
279 {
280 c = 0;
281 b = 1;
282 }
283 else
284 c = b = 1;
285
286 DIFF(r) = 0;
287 DIFF(p) = b - 1;
288 DIFF(q) = 1 - c;
289
290 return r;
291 }
292
293 // Double rotate right with counter update
294 [[gnu::always_inline]]
295 static Node * doubleRotateRight(Node *p) noexcept
296 {
297 assert(DIFF(p) == 2 or DIFF(p) == -2);
298 assert(LLINK(p) != Node::NullPtr and RLINK(LLINK(p)) != Node::NullPtr);
299
300 Node *q = LLINK(p);
301 Node *r = RLINK(q);
302 LLINK(p) = RLINK(r);
303 RLINK(q) = LLINK(r);
304 RLINK(r) = p;
305 LLINK(r) = q;
306
307 // Update counters
308 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
309 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
310 COUNT(r) = COUNT(LLINK(r)) + COUNT(RLINK(r)) + 1;
311
312 unsigned char b, c;
313 if (DIFF(r) == 1)
314 {
315 c = 1;
316 b = 0;
317 }
318 else if (DIFF(r) == -1)
319 {
320 c = 0;
321 b = 1;
322 }
323 else
324 c = b = 1;
325
326 DIFF(r) = 0;
327 DIFF(p) = 1 - c;
328 DIFF(q) = b - 1;
329
330 return r;
331 }
332
337
338 static Rotation_Type rotation_type(Node *p) noexcept
339 {
340 assert(DIFF(p) == 2 or DIFF(p) == -2);
341
342 Node *pc;
343 if (DIFF(p) == 2)
344 {
345 pc = RLINK(p);
346 if (DIFF(pc) == 1 or DIFF(pc) == 0)
347 return ROTATE_LEFT;
348 return DOUBLE_ROTATE_LEFT;
349 }
350
351 pc = LLINK(p);
352 if (DIFF(pc) == -1 or DIFF(pc) == 0)
353 return ROTATE_RIGHT;
354
355 return DOUBLE_ROTATE_RIGHT;
356 }
357
358 static Node * restore_avl(Node *p, Node *pp) noexcept
359 {
360 assert(LLINK(pp) == p or RLINK(pp) == p);
361 assert(DIFF(p) == -2 or DIFF(p) == 2);
362
363 Node **link = LLINK(pp) == p ? &LLINK(pp) : &RLINK(pp);
364 switch (rotation_type(p))
365 {
366 case ROTATE_LEFT: return *link = rotateLeft(p);
367 case ROTATE_RIGHT: return *link = rotateRight(p);
368 case DOUBLE_ROTATE_LEFT: return *link = doubleRotateLeft(p);
369 case DOUBLE_ROTATE_RIGHT: return *link = doubleRotateRight(p);
370 default:
371 AH_ERROR("Invalid rotation type");
372 break;
373 }
374
375 return nullptr;
376 }
377
379 {
380 Node *pp = avl_stack.pop();
381 if (LLINK(pp) == p)
382 --DIFF(pp);
383 else
384 ++DIFF(pp);
385
386 if (DIFF(pp) == 0)
387 {
389 return;
390 }
391
392 if (avl_stack_empty())
393 return;
394
395 do
396 {
397 Node *gpp = avl_stack.pop();
398 if (LLINK(gpp) == pp)
399 --DIFF(gpp);
400 else
401 ++DIFF(gpp);
402
403 if (DIFF(gpp) == 0)
404 break;
405 if (DIFF(gpp) == -2 or DIFF(gpp) == 2)
406 {
407 Node *ggpp = avl_stack.pop();
409 break;
410 }
411
412 pp = gpp;
413 }
414 while (not avl_stack_empty());
415
417 }
418
419 Node * swapWithSuccessor(Node *p, Node *& pp) noexcept
420 {
422
423 Node *fSucc = p;
424 Node *succ = RLINK(p);
425
426 avl_stack.push(succ);
427
428 while (LLINK(succ) != Node::NullPtr)
429 {
430 fSucc = succ;
431 succ = LLINK(succ);
432 avl_stack.push(succ);
433 }
434
435 ref_to_stack_top = succ;
436 avl_stack.top() = p;
437
438 if (LLINK(pp) == p)
439 LLINK(pp) = succ;
440 else
441 RLINK(pp) = succ;
442
443 LLINK(succ) = LLINK(p);
444 LLINK(p) = Node::NullPtr;
445
446 if (RLINK(p) == succ)
447 {
448 RLINK(p) = RLINK(succ);
449 RLINK(succ) = p;
450 pp = succ;
451 }
452 else
453 {
454 Node *succr = RLINK(succ);
455 RLINK(succ) = RLINK(p);
456 LLINK(fSucc) = p;
457 RLINK(p) = succr;
458 pp = fSucc;
459 }
460
461 // Swap balance factors
462 DIFF(succ) = DIFF(p);
463
464 // Swap counters
465 COUNT(succ) = COUNT(p);
466
467 return succ;
468 }
469
471 {
472 Node *pp = avl_stack.top(1);
473 Node *ppp = avl_stack.popn(3);
474
475 while (true)
476 {
477 if (left_deficit)
478 ++DIFF(pp);
479 else
480 --DIFF(pp);
481
482 if (DIFF(pp) == -2 or DIFF(pp) == 2)
483 pp = restore_avl(pp, ppp);
484
485 if (DIFF(pp) != 0 or pp == root)
486 break;
487
488 left_deficit = LLINK(ppp) == pp;
489 pp = ppp;
490 ppp = avl_stack.pop();
491 }
492
494 }
495
496 // Update counters along the stack after insertion
498 {
499 // Stack contains: [head_ptr, ..., nodes in path, ..., closest to insertion]
500 // top(0) = closest node, top(size-1) = head_ptr (don't update)
501 const size_t sz = avl_stack.size();
502 for (size_t i = 0; i < sz - 1; ++i)
503 ++COUNT(avl_stack.top(i));
504 }
505
506 // Update counters along the stack after deletion
508 {
509 const size_t sz = avl_stack.size();
510 for (size_t i = 0; i < sz - 1; ++i)
511 --COUNT(avl_stack.top(i));
512 }
513
514 public:
515 using key_type = Key;
516
518 [[nodiscard]] constexpr Compare &key_comp() noexcept { return cmp; }
519
521 [[nodiscard]] constexpr Compare &get_compare() noexcept { return key_comp(); }
522
523 Gen_Avl_Tree_Rk(Compare cmf_fct = Compare()) noexcept
524 : avl_stack(Node::MaxHeight), head_ptr(&head_node),
526 {
528 }
529
535 void swap(Gen_Avl_Tree_Rk & tree) noexcept
536 {
537 std::swap(root, tree.root);
538 std::swap(cmp, tree.cmp);
539 }
540
542
544 [[nodiscard]] constexpr Node *&getRoot() noexcept { return root; }
545
547 [[nodiscard]] constexpr Node * getRoot() const noexcept { return root; }
548
550 [[nodiscard]] size_t size() const noexcept { return COUNT(root); }
551
553 [[nodiscard]] constexpr bool is_empty() const noexcept { return root == Node::NullPtr; }
554
557 [[nodiscard]] Node * search(const Key & key) const noexcept
558 {
560 return result == Node::NullPtr ? nullptr : result;
561 }
562
568 [[nodiscard]] Node * insert(Node *p) noexcept
569 {
570 if (root == Node::NullPtr)
571 return root = p;
572
573 signed char cmp_result = CmpEqual;
575 if (cmp_result == CmpLess)
576 LLINK(pp) = p;
577 else if (cmp_result == CmpGreater)
578 RLINK(pp) = p;
579 else
580 {
582 return nullptr;
583 }
584
587
588 return p;
589 }
590
599 {
600 if (root == Node::NullPtr)
601 return root = p;
602
603 signed char cmp_result = CmpEqual;
605 if (cmp_result == CmpLess)
606 LLINK(pp) = p;
607 else if (cmp_result == CmpGreater)
608 RLINK(pp) = p;
609 else
610 {
612 return pp;
613 }
614
617
618 return p;
619 }
620
622 [[nodiscard]] Node * insert_dup(Node *p) noexcept
623 {
624 if (root == Node::NullPtr)
625 return root = p;
626
627 signed char cmp_result = CmpEqual;
629 if (cmp_result == CmpLess)
630 LLINK(pp) = p;
631 else
632 RLINK(pp) = p;
633
636
637 return p;
638 }
639
642 [[nodiscard]] Node * remove(const Key & key) noexcept
643 {
644 if (root == Node::NullPtr)
645 return nullptr;
646
647 signed char cmp_result = CmpEqual;
649 if (cmp_result != CmpEqual)
650 {
652 return nullptr;
653 }
654
655 Node *pp = avl_stack.top(1);
656 bool left_deficit;
657
658 while (true)
659 {
660 left_deficit = LLINK(pp) == p;
661 if (LLINK(p) == Node::NullPtr)
662 {
663 if (LLINK(pp) == p)
664 LLINK(pp) = RLINK(p);
665 else
666 RLINK(pp) = RLINK(p);
667 break;
668 }
669
670 if (RLINK(p) == Node::NullPtr)
671 {
672 if (LLINK(pp) == p)
673 LLINK(pp) = LLINK(p);
674 else
675 RLINK(pp) = LLINK(p);
676 break;
677 }
678
680 }
681
682 p->reset();
683
684 if (pp == head_ptr)
685 {
687 return p;
688 }
689
692
693 return p;
694 }
695
703 Node * select(const size_t i) const
704 {
705 return Aleph::select(root, i);
706 }
707
714 std::pair<long, Node *> position(const Key & key) const noexcept
715 {
716 std::pair<long, Node *> ret_val;
717
719 inorder_position(root, key, ret_val.second);
720
721 return ret_val;
722 }
723
729 std::pair<long, Node *> find_position(const Key & key) const noexcept
730 {
731 std::pair<long, Node *> r(-2, nullptr);
732
734 find_position(root, key, r.second);
735
736 return r;
737 }
738
741 {
743 }
744
745 private:
746 // Compute height of AVL tree in O(log n) using balance factors
747 static size_t avl_height(Node *p) noexcept
748 {
749 size_t h = 0;
750 while (p != Node::NullPtr)
751 {
752 ++h;
753 // Follow the taller subtree
754 if (DIFF(p) >= 0)
755 p = RLINK(p); // right is taller or equal
756 else
757 p = LLINK(p); // left is taller
758 }
759 return h;
760 }
761
762 // Extract and remove the minimum node from tree rooted at p
763 // Returns the extracted node and updates p to the new root
764 static Node * extract_min(Node *& p) noexcept
765 {
766 if (p == Node::NullPtr)
767 return Node::NullPtr;
768
769 if (LLINK(p) == Node::NullPtr)
770 {
771 Node *ret = p;
772 p = RLINK(p);
773 LLINK(ret) = RLINK(ret) = Node::NullPtr;
774 COUNT(ret) = 1;
775 DIFF(ret) = 0;
776 return ret;
777 }
778
779 // Stack for rebalancing
780 FixedStack<Node **> stack(Node::MaxHeight);
781 Node **pp = &p;
782
783 while (LLINK(*pp) != Node::NullPtr)
784 {
785 stack.push(pp);
786 pp = &LLINK(*pp);
787 }
788
789 Node *ret = *pp;
790 *pp = RLINK(ret);
791
792 // Update counts and rebalance going up
793 while (not stack.is_empty())
794 {
795 Node **parent_ptr = stack.pop();
796 Node *parent = *parent_ptr;
797 --COUNT(parent);
798 ++DIFF(parent); // left subtree got shorter
799
800 if (DIFF(parent) == 2)
801 {
802 // Need to rebalance
803 Node *q = RLINK(parent);
804 if (DIFF(q) >= 0)
805 *parent_ptr = rotateLeft(parent);
806 else
807 *parent_ptr = doubleRotateLeft(parent);
808 }
809 else if (DIFF(parent) == 1)
810 break; // height didn't change
811 }
812
813 LLINK(ret) = RLINK(ret) = Node::NullPtr;
814 COUNT(ret) = 1;
815 DIFF(ret) = 0;
816 return ret;
817 }
818
819 // Extract and remove the maximum node from tree rooted at p
820 static Node * extract_max(Node *& p) noexcept
821 {
822 if (p == Node::NullPtr)
823 return Node::NullPtr;
824
825 if (RLINK(p) == Node::NullPtr)
826 {
827 Node *ret = p;
828 p = LLINK(p);
829 LLINK(ret) = RLINK(ret) = Node::NullPtr;
830 COUNT(ret) = 1;
831 DIFF(ret) = 0;
832 return ret;
833 }
834
835 FixedStack<Node **> stack(Node::MaxHeight);
836 Node **pp = &p;
837
838 while (RLINK(*pp) != Node::NullPtr)
839 {
840 stack.push(pp);
841 pp = &RLINK(*pp);
842 }
843
844 Node *ret = *pp;
845 *pp = LLINK(ret);
846
847 while (not stack.is_empty())
848 {
849 Node **parent_ptr = stack.pop();
850 Node *parent = *parent_ptr;
851 --COUNT(parent);
852 --DIFF(parent); // right subtree got shorter
853
854 if (DIFF(parent) == -2)
855 {
856 Node *q = LLINK(parent);
857 if (DIFF(q) <= 0)
858 *parent_ptr = rotateRight(parent);
859 else
860 *parent_ptr = doubleRotateRight(parent);
861 }
862 else if (DIFF(parent) == -1)
863 break;
864 }
865
866 LLINK(ret) = RLINK(ret) = Node::NullPtr;
867 COUNT(ret) = 1;
868 DIFF(ret) = 0;
869 return ret;
870 }
871
872 // Recursive join of two AVL trees where all keys in t1 < all keys in t2
873 // h1 and h2 are the heights of t1 and t2 respectively
874 static Node * join_exclusive_rec(Node *t1, size_t h1,
875 Node *t2, size_t h2) noexcept
876 {
877 if (t1 == Node::NullPtr)
878 return t2;
879 if (t2 == Node::NullPtr)
880 return t1;
881
882 if (h1 >= h2)
883 {
884 // Extract max from t1 to use as pivot
886 if (t1 != Node::NullPtr)
887 h1 = avl_height(t1);
888 else
889 h1 = 0;
890
891 return join_with_pivot(t1, h1, pivot, t2, h2);
892 }
893 // Extract min from t2 to use as pivot
895 if (t2 != Node::NullPtr)
896 h2 = avl_height(t2);
897 else
898 h2 = 0;
899
900 return join_with_pivot(t1, h1, pivot, t2, h2);
901 }
902
903 // Join t1 and t2 using pivot as the connecting node
904 // All keys in t1 < pivot < all keys in t2
905 static Node * join_with_pivot(Node *t1, const size_t h1, Node *pivot,
906 Node *t2, const size_t h2) noexcept
907 {
908 if (h1 <= h2 + 1 and h2 <= h1 + 1)
909 {
910 // Heights are close enough, pivot becomes root
911 LLINK(pivot) = t1;
912 RLINK(pivot) = t2;
913 DIFF(pivot) = static_cast<signed char>(h2) - static_cast<signed char>(h1);
914 COUNT(pivot) = COUNT(t1) + COUNT(t2) + 1;
915 return pivot;
916 }
917
918 if (h1 > h2)
919 {
920 // t1 is taller, descend into right spine of t1
921 Node *result = join_right(t1, h1, pivot, t2, h2);
922 return result;
923 }
924 // t2 is taller, descend into left spine of t2
925 Node *result = join_left(t1, h1, pivot, t2, h2);
926 return result;
927 }
928
929 // Join when h1 > h2 + 1: descend right spine of t1
930 static Node * join_right(Node *t1, const size_t h1, Node *pivot,
931 Node *t2, const size_t h2) noexcept
932 {
933 FixedStack<Node **> stack(Node::MaxHeight);
934 Node **pp = &t1;
935 size_t curr_h = h1;
936
937 // Descend right spine until we find a subtree of appropriate height
938 while (curr_h > h2 + 1 and *pp != Node::NullPtr)
939 {
940 stack.push(pp);
941 if (DIFF(*pp) >= 0)
942 curr_h--; // right child has height curr_h - 1
943 else
944 curr_h -= 2; // right child has height curr_h - 2 (since left is curr_h - 1)
945
946 pp = &RLINK(*pp);
947 }
948
949 // Now *pp points to a subtree of height <= h2 + 1
950 // Join pivot with *pp and t2
951 LLINK(pivot) = *pp;
952 RLINK(pivot) = t2;
953 const size_t left_h = (*pp != Node::NullPtr) ? avl_height(*pp) : 0;
954 DIFF(pivot) = static_cast<signed char>(h2) - static_cast<signed char>(left_h);
955 COUNT(pivot) = COUNT(*pp) + COUNT(t2) + 1;
956 *pp = pivot;
957
958 // Rebalance going up
959 while (not stack.is_empty())
960 {
961 Node **parent_ptr = stack.pop();
962 Node *parent = *parent_ptr;
963 COUNT(parent) = COUNT(LLINK(parent)) + COUNT(RLINK(parent)) + 1;
964
965 const size_t new_right_h = avl_height(RLINK(parent));
966 const size_t new_left_h = avl_height(LLINK(parent));
967 DIFF(parent) = static_cast<signed char>(new_right_h) -
968 static_cast<signed char>(new_left_h);
969
970 if (DIFF(parent) == 2)
971 {
972 if (Node *q = RLINK(parent); DIFF(q) >= 0)
973 *parent_ptr = rotateLeft(parent);
974 else
975 *parent_ptr = doubleRotateLeft(parent);
976 }
977 }
978
979 return t1;
980 }
981
982 // Join when h2 > h1 + 1: descend left spine of t2
983 static Node * join_left(Node *t1, const size_t h1, Node *pivot,
984 Node *t2, const size_t h2) noexcept
985 {
986 FixedStack<Node **> stack(Node::MaxHeight);
987 Node **pp = &t2;
988 size_t curr_h = h2;
989
990 while (curr_h > h1 + 1 and *pp != Node::NullPtr)
991 {
992 stack.push(pp);
993 if (DIFF(*pp) <= 0)
994 curr_h--;
995 else
996 curr_h -= 2;
997
998 pp = &LLINK(*pp);
999 }
1000
1001 RLINK(pivot) = *pp;
1002 LLINK(pivot) = t1;
1003 const size_t right_h = (*pp != Node::NullPtr) ? avl_height(*pp) : 0;
1004 DIFF(pivot) = static_cast<signed char>(right_h) - static_cast<signed char>(h1);
1005 COUNT(pivot) = COUNT(t1) + COUNT(*pp) + 1;
1006 *pp = pivot;
1007
1008 while (not stack.is_empty())
1009 {
1010 Node **parent_ptr = stack.pop();
1011 Node *parent = *parent_ptr;
1012 COUNT(parent) = COUNT(LLINK(parent)) + COUNT(RLINK(parent)) + 1;
1013
1014 const size_t new_right_h = avl_height(RLINK(parent));
1015 const size_t new_left_h = avl_height(LLINK(parent));
1016 DIFF(parent) = static_cast<signed char>(new_right_h) -
1017 static_cast<signed char>(new_left_h);
1018
1019 if (DIFF(parent) == -2)
1020 {
1021 if (Node *q = LLINK(parent); DIFF(q) <= 0)
1022 *parent_ptr = rotateRight(parent);
1023 else
1024 *parent_ptr = doubleRotateRight(parent);
1025 }
1026 }
1027
1028 return t2;
1029 }
1030
1031 // Split by key recursively
1032 // Returns the node containing key (or NullPtr if not found)
1033 // t1 gets all keys < key, t2 gets all keys > key
1034 Node * split_key_rec(Node *p, const Key & key,
1035 Node *& t1, Node *& t2) noexcept
1036 {
1037 if (p == Node::NullPtr)
1038 {
1039 t1 = t2 = Node::NullPtr;
1040 return Node::NullPtr;
1041 }
1042
1043 Node *found;
1044 if (cmp(key, KEY(p)))
1045 {
1046 // key < p->key, go left
1047 Node *left_t2;
1048 found = split_key_rec(LLINK(p), key, t1, left_t2);
1049
1050 // p and its right subtree go to t2
1051 LLINK(p) = Node::NullPtr;
1052 const size_t left_t2_h = (left_t2 != Node::NullPtr) ? avl_height(left_t2) : 0;
1053 const size_t right_h = (RLINK(p) != Node::NullPtr) ? avl_height(RLINK(p)) : 0;
1054
1055 Node *right_tree = RLINK(p);
1056 RLINK(p) = Node::NullPtr;
1057 COUNT(p) = 1;
1058 DIFF(p) = 0;
1059
1061 }
1062 else if (cmp(KEY(p), key))
1063 {
1064 // key > p->key, go right
1065 Node *right_t1;
1066 found = split_key_rec(RLINK(p), key, right_t1, t2);
1067
1068 // p and its left subtree go to t1
1069 RLINK(p) = Node::NullPtr;
1070 const size_t right_t1_h = (right_t1 != Node::NullPtr) ? avl_height(right_t1) : 0;
1071 const size_t left_h = (LLINK(p) != Node::NullPtr) ? avl_height(LLINK(p)) : 0;
1072
1073 Node *left_tree = LLINK(p);
1074 LLINK(p) = Node::NullPtr;
1075 COUNT(p) = 1;
1076 DIFF(p) = 0;
1077
1079 }
1080 else
1081 {
1082 // Found the key
1083 t1 = LLINK(p);
1084 t2 = RLINK(p);
1085 LLINK(p) = RLINK(p) = Node::NullPtr;
1086 COUNT(p) = 1;
1087 DIFF(p) = 0;
1088 found = p;
1089 }
1090
1091 return found;
1092 }
1093
1094 // Split by key for duplicates: keys <= key go to t1, keys > key go to t2
1095 void split_key_dup_rec(Node *p, const Key & key,
1096 Node *& t1, Node *& t2) noexcept
1097 {
1098 if (p == Node::NullPtr)
1099 {
1100 t1 = t2 = Node::NullPtr;
1101 return;
1102 }
1103
1104 if (cmp(key, KEY(p)))
1105 {
1106 // key < p->key, p goes to t2
1107 Node *left_t2;
1108 split_key_dup_rec(LLINK(p), key, t1, left_t2);
1109
1110 LLINK(p) = Node::NullPtr;
1111 const size_t left_t2_h = (left_t2 != Node::NullPtr) ? avl_height(left_t2) : 0;
1112 const size_t right_h = (RLINK(p) != Node::NullPtr) ? avl_height(RLINK(p)) : 0;
1113
1114 Node *right_tree = RLINK(p);
1115 RLINK(p) = Node::NullPtr;
1116 COUNT(p) = 1;
1117 DIFF(p) = 0;
1118
1120 }
1121 else
1122 {
1123 // key >= p->key, p goes to t1
1124 Node *right_t1;
1126
1127 RLINK(p) = Node::NullPtr;
1128 const size_t right_t1_h = (right_t1 != Node::NullPtr) ? avl_height(right_t1) : 0;
1129 const size_t left_h = (LLINK(p) != Node::NullPtr) ? avl_height(LLINK(p)) : 0;
1130
1131 Node *left_tree = LLINK(p);
1132 LLINK(p) = Node::NullPtr;
1133 COUNT(p) = 1;
1134 DIFF(p) = 0;
1135
1137 }
1138 }
1139
1140 // Split by position recursively
1141 // Nodes with position < pos go to t1, nodes with position >= pos go to t2
1142 void split_pos_rec(Node *p, size_t pos, Node *& t1, Node *& t2) noexcept
1143 {
1144 if (p == Node::NullPtr)
1145 {
1146 t1 = t2 = Node::NullPtr;
1147 return;
1148 }
1149
1150 if (const size_t left_count = COUNT(LLINK(p)); pos <= left_count)
1151 {
1152 // Split point is in left subtree or at p
1153 Node *left_t2;
1154 split_pos_rec(LLINK(p), pos, t1, left_t2);
1155
1156 // p goes to t2
1157 LLINK(p) = Node::NullPtr;
1158 const size_t left_t2_h = (left_t2 != Node::NullPtr) ? avl_height(left_t2) : 0;
1159 const size_t right_h = (RLINK(p) != Node::NullPtr) ? avl_height(RLINK(p)) : 0;
1160
1161 Node *right_tree = RLINK(p);
1162 RLINK(p) = Node::NullPtr;
1163 COUNT(p) = 1;
1164 DIFF(p) = 0;
1165
1167 }
1168 else
1169 {
1170 // Split point is in right subtree
1171 Node *right_t1;
1172 split_pos_rec(RLINK(p), pos - left_count - 1, right_t1, t2);
1173
1174 // p goes to t1
1175 RLINK(p) = Node::NullPtr;
1176 const size_t right_t1_h = (right_t1 != Node::NullPtr) ? avl_height(right_t1) : 0;
1177 const size_t left_h = (LLINK(p) != Node::NullPtr) ? avl_height(LLINK(p)) : 0;
1178
1179 Node *left_tree = LLINK(p);
1180 LLINK(p) = Node::NullPtr;
1181 COUNT(p) = 1;
1182 DIFF(p) = 0;
1183
1185 }
1186 }
1187
1188 public:
1198 {
1199 if (t.root == Node::NullPtr)
1200 return;
1201
1202 if (root == Node::NullPtr)
1203 {
1204 root = t.root;
1205 t.root = Node::NullPtr;
1206 return;
1207 }
1208
1209 // Collect nodes from t in preorder and insert them one by one
1210 // This is O(m log(n+m)) but guarantees correctness
1211 FixedStack<Node *> stack(Node::MaxHeight);
1212 stack.push(t.root);
1213 t.root = Node::NullPtr;
1214
1215 while (not stack.is_empty())
1216 {
1217 Node *p = stack.pop();
1218 Node *left = LLINK(p);
1219 Node *right = RLINK(p);
1220
1221 // Reset node and insert
1222 LLINK(p) = RLINK(p) = Node::NullPtr;
1223 COUNT(p) = 1;
1224 DIFF(p) = 0;
1225 (void)insert(p);
1226
1227 if (right != Node::NullPtr)
1228 stack.push(right);
1229 if (left != Node::NullPtr)
1230 stack.push(left);
1231 }
1232 }
1233
1247 Node * split_key(const Key & key, Gen_Avl_Tree_Rk & t1,
1248 Gen_Avl_Tree_Rk & t2) noexcept
1249 {
1250 if (root == Node::NullPtr)
1251 return nullptr;
1252
1253 // Simple O(n) implementation: iterate through tree and partition
1254 Node *found = nullptr;
1255 FixedStack<Node *> stack(Node::MaxHeight);
1256 stack.push(root);
1257 root = Node::NullPtr;
1258
1259 while (not stack.is_empty())
1260 {
1261 Node *p = stack.pop();
1262 Node *left = LLINK(p);
1263 Node *right = RLINK(p);
1264
1265 if (right != Node::NullPtr)
1266 stack.push(right);
1267 if (left != Node::NullPtr)
1268 stack.push(left);
1269
1270 LLINK(p) = RLINK(p) = Node::NullPtr;
1271 COUNT(p) = 1;
1272 DIFF(p) = 0;
1273
1274 if (cmp(KEY(p), key))
1275 (void)t1.insert(p);
1276 else if (cmp(key, KEY(p)))
1277 (void)t2.insert(p);
1278 else
1279 found = p; // Found the key
1280 }
1281
1282 return found;
1283 }
1284
1297 void split_key_dup(const Key & key, Gen_Avl_Tree_Rk & t1,
1298 Gen_Avl_Tree_Rk & t2) noexcept
1299 {
1300 if (root == Node::NullPtr)
1301 return;
1302
1303 FixedStack<Node *> stack(Node::MaxHeight);
1304 stack.push(root);
1305 root = Node::NullPtr;
1306
1307 while (not stack.is_empty())
1308 {
1309 Node *p = stack.pop();
1310 Node *left = LLINK(p);
1311 Node *right = RLINK(p);
1312
1313 if (right != Node::NullPtr)
1314 stack.push(right);
1315 if (left != Node::NullPtr)
1316 stack.push(left);
1317
1318 LLINK(p) = RLINK(p) = Node::NullPtr;
1319 COUNT(p) = 1;
1320 DIFF(p) = 0;
1321
1322 if (cmp(key, KEY(p)))
1323 (void)t2.insert(p);
1324 else
1325 (void)t1.insert_dup(p);
1326 }
1327 }
1328
1341 void split_pos(const size_t pos, Gen_Avl_Tree_Rk & t1,
1342 Gen_Avl_Tree_Rk & t2) noexcept
1343 {
1344 if (root == Node::NullPtr)
1345 return;
1346
1347 if (pos == 0)
1348 {
1349 t2.root = root;
1350 root = Node::NullPtr;
1351 return;
1352 }
1353
1354 if (pos >= size())
1355 {
1356 t1.root = root;
1357 root = Node::NullPtr;
1358 return;
1359 }
1360
1361 // Simple O(n) implementation using inorder traversal
1362 size_t count = 0;
1363 FixedStack<Node *> stack(Node::MaxHeight);
1364 Node *curr = root;
1365 root = Node::NullPtr;
1366
1367 // Inorder traversal
1368 while (curr != Node::NullPtr or not stack.is_empty())
1369 {
1370 while (curr != Node::NullPtr)
1371 {
1372 stack.push(curr);
1373 Node *left = LLINK(curr);
1374 LLINK(curr) = Node::NullPtr; // Disconnect
1375 curr = left;
1376 }
1377
1378 curr = stack.pop();
1379 Node *right = RLINK(curr);
1380 RLINK(curr) = Node::NullPtr;
1381 COUNT(curr) = 1;
1382 DIFF(curr) = 0;
1383
1384 if (count < pos)
1385 (void)t1.insert(curr);
1386 else
1387 (void)t2.insert(curr);
1388
1389 ++count;
1390 curr = right;
1391 }
1392 }
1393
1402 class Iterator : public BinTreeXt_Iterator<Gen_Avl_Tree_Rk, Node, Key, Compare>
1403 {
1405
1406 public:
1407 using Base::Base;
1408 using Base::operator=;
1409 }; // end class Iterator
1410 };
1411
1412
1422 template <typename Key, class Compare = Aleph::less<Key>>
1423 struct Avl_Tree_Rk : public Gen_Avl_Tree_Rk<AvlNodeRk, Key, Compare>
1424 {
1426 using Base::Base;
1427 };
1428
1429
1439 template <typename Key, class Compare = Aleph::less<Key>>
1440 struct Avl_Tree_Rk_Vtl : public Gen_Avl_Tree_Rk<AvlNodeRkVtl, Key, Compare>
1441 {
1443 using Base::Base;
1444 };
1445} // end namespace Aleph
1446
1447# endif // TPL_AVLRK_H
Exception handling system with formatted messages for Aleph-w.
#define AH_ERROR(format, args...)
Print an error message (always enabled).
Definition ahDefs.H:271
Standard functor implementations and comparison objects.
AVL tree node with rank (subtree count).
#define DIFF(p)
Access the balance factor of node p.
Definition avlNode.H:95
@ KEY
Definition btreepic.C:169
long double h
Definition btreepic.C:154
Base iterator template for ranked binary search trees.
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
Fixed length stack.
T & push(const T &data) noexcept
Push a copy of data
size_t size() const noexcept
Return the number of elements stored in the stack.
T popn(const int &n) noexcept
Perform in constant time n pops.
bool is_empty() const noexcept
Return true if stack is empty.
T & top() const noexcept
Return a modifiable referemce to stack's top.
T pop() noexcept
Pop by moving the top of stack.
Iterator over the nodes.
Definition tpl_avlRk.H:1403
AVL balanced binary search tree with rank (order statistics).
Definition tpl_avlRk.H:111
Node * insert(Node *p) noexcept
Insert the node pointed by p in the tree.
Definition tpl_avlRk.H:568
void split_key_dup_rec(Node *p, const Key &key, Node *&t1, Node *&t2) noexcept
Definition tpl_avlRk.H:1095
static Node * join_with_pivot(Node *t1, const size_t h1, Node *pivot, Node *t2, const size_t h2) noexcept
Definition tpl_avlRk.H:905
constexpr Compare & key_comp() noexcept
The key type.
Definition tpl_avlRk.H:518
NodeType< Key > Node
Definition tpl_avlRk.H:113
Node * search_and_stack_avl(const Key &key, signed char &cmp_result) noexcept
Definition tpl_avlRk.H:126
static size_t avl_height(Node *p) noexcept
Definition tpl_avlRk.H:747
constexpr Node *& getRoot() noexcept
Return a modifiable reference to tree's root.
Definition tpl_avlRk.H:544
static Node * join_exclusive_rec(Node *t1, size_t h1, Node *t2, size_t h2) noexcept
Definition tpl_avlRk.H:874
Gen_Avl_Tree_Rk(Compare cmf_fct=Compare()) noexcept
Definition tpl_avlRk.H:523
Node * select(const size_t i) const
Return the i-th node in order sense.
Definition tpl_avlRk.H:703
Node * search_dup_and_stack_avl(const Key &key, signed char &cmp_result) noexcept
Definition tpl_avlRk.H:172
bool avl_stack_empty() noexcept
Definition tpl_avlRk.H:122
void update_counters_after_insertion() noexcept
Definition tpl_avlRk.H:497
static Node * join_left(Node *t1, const size_t h1, Node *pivot, Node *t2, const size_t h2) noexcept
Definition tpl_avlRk.H:983
Node * search_or_insert(Node *p) noexcept
Search or insert a key.
Definition tpl_avlRk.H:598
static Rotation_Type rotation_type(Node *p) noexcept
Definition tpl_avlRk.H:338
void restore_avl_after_insertion(Node *p) noexcept
Definition tpl_avlRk.H:378
std::pair< long, Node * > find_position(const Key &key) const noexcept
Find the inorder position of a key in the tree.
Definition tpl_avlRk.H:729
Node * split_key_rec(Node *p, const Key &key, Node *&t1, Node *&t2) noexcept
Definition tpl_avlRk.H:1034
Node * remove(const Key &key) noexcept
Remove from tree the node containing key.
Definition tpl_avlRk.H:642
static Node * restore_avl(Node *p, Node *pp) noexcept
Definition tpl_avlRk.H:358
static Node * rotateLeft(Node *p) noexcept
Definition tpl_avlRk.H:205
size_t size() const noexcept
Return the number of nodes in the tree.
Definition tpl_avlRk.H:550
void split_pos_rec(Node *p, size_t pos, Node *&t1, Node *&t2) noexcept
Definition tpl_avlRk.H:1142
static Node * extract_max(Node *&p) noexcept
Definition tpl_avlRk.H:820
virtual ~Gen_Avl_Tree_Rk() noexcept
Definition tpl_avlRk.H:541
static Node * extract_min(Node *&p) noexcept
Definition tpl_avlRk.H:764
static Node * rotateRight(Node *p) noexcept
Definition tpl_avlRk.H:230
void join_exclusive(Gen_Avl_Tree_Rk &t) noexcept
Join this tree exclusively with another tree.
Definition tpl_avlRk.H:1197
Node * swapWithSuccessor(Node *p, Node *&pp) noexcept
Definition tpl_avlRk.H:419
constexpr bool is_empty() const noexcept
Return true if tree is empty.
Definition tpl_avlRk.H:553
static Node * doubleRotateLeft(Node *p) noexcept
Definition tpl_avlRk.H:255
constexpr Compare & get_compare() noexcept
Definition tpl_avlRk.H:521
void swap(Gen_Avl_Tree_Rk &tree) noexcept
Swap in constant time all the items of this with the items of tree.
Definition tpl_avlRk.H:535
Node * insert_dup(Node *p) noexcept
Insert the node p without testing for key duplicity.
Definition tpl_avlRk.H:622
void restore_avl_after_deletion(bool left_deficit) noexcept
Definition tpl_avlRk.H:470
void split_key_dup(const Key &key, Gen_Avl_Tree_Rk &t1, Gen_Avl_Tree_Rk &t2) noexcept
Split tree by key including duplicates.
Definition tpl_avlRk.H:1297
static Node * doubleRotateRight(Node *p) noexcept
Definition tpl_avlRk.H:295
Node * split_key(const Key &key, Gen_Avl_Tree_Rk &t1, Gen_Avl_Tree_Rk &t2) noexcept
Split tree by key.
Definition tpl_avlRk.H:1247
void split_pos(const size_t pos, Gen_Avl_Tree_Rk &t1, Gen_Avl_Tree_Rk &t2) noexcept
Split tree by inorder position.
Definition tpl_avlRk.H:1341
constexpr Node * getRoot() const noexcept
Return a modifiable reference to tree's root.
Definition tpl_avlRk.H:547
bool verify() const noexcept
Return true if the tree is a valid AVL tree with correct counters.
Definition tpl_avlRk.H:740
Node * search(const Key &key) const noexcept
Search a node containing key; if found, then a pointer to the node containing it is returned; otherwi...
Definition tpl_avlRk.H:557
void update_counters_after_deletion() noexcept
Definition tpl_avlRk.H:507
void clean_avl_stack() noexcept
Definition tpl_avlRk.H:124
FixedStack< Node * > avl_stack
The type of node.
Definition tpl_avlRk.H:116
std::pair< long, Node * > position(const Key &key) const noexcept
Compute the inorder position of a key.
Definition tpl_avlRk.H:714
static Node * join_right(Node *t1, const size_t h1, Node *pivot, Node *t2, const size_t h2) noexcept
Definition tpl_avlRk.H:930
long inorder_position(Node *r, const typename Node::key_type &key, Node *&p, Compare &cmp) noexcept
Compute the inorder position of a key.
bool check_rank_tree(Node *root) noexcept
Return true if root is a valid extended binary tree.
constexpr Node *& RLINK(Node *p) noexcept
Return the right tree of p.
auto & COUNT(Node *p) noexcept
Return the number of nodes of the tree fron p is root.
Node * select(Node *r, const size_t pos)
Iterative selection of a node according to inorder position.
constexpr Node *& LLINK(Node *p) noexcept
Return a pointer to left subtree.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool is_avl_rk(Node *p)
Verify if tree rooted at p is a valid AVL tree with correct counters.
Definition avlNodeRk.H:89
@ CmpGreater
First argument is greater than second.
@ CmpLess
First argument is less than second.
@ CmpEqual
Arguments are equal.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
AVL binary search tree with virtual destructor in its nodes and with subtree counters for select/posi...
Definition tpl_avlRk.H:1441
AVL binary search tree with nodes without virtual destructor and with subtree counters for select/pos...
Definition tpl_avlRk.H:1424
Stack implementations backed by dynamic or fixed arrays.
Utility functions for binary tree operations.
Extended binary node with subtree count.
Binary tree operations (split, join, rotate).