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# include <ah-concepts.H>
62
63using namespace Aleph;
64
65namespace Aleph
66{
110 template <template <typename> class NodeType, typename Key, class Compare>
113 {
114 public:
116
117 private:
122 Compare cmp;
123
125 {
126 return not avl_stack.is_empty()
127 and avl_stack.size() == 1
129 }
130
132 {
133 if (avl_stack.is_empty())
134 {
136 return;
137 }
138
139 if (avl_stack.base() != head_ptr)
140 {
143 return;
144 }
145
146 if (const size_t to_pop = avl_stack.size() - 1; to_pop > 0)
147 avl_stack.popn(static_cast<int>(to_pop));
148 }
149
150 Node * search_and_stack_avl(const Key & key,
151 signed char & cmp_result) noexcept
152 {
154
155 Node *p = root;
156 Node *candidate = nullptr; // Tracks potential duplicate when going right
157 size_t candidate_pos = 0; // Stack size when candidate was set
158
159 do
160 {
163 avl_stack.push(p);
164 if (cmp(key, KEY(p))) // key < KEY(p)
165 {
167 p = LLINK(p);
168 }
169 else // key >= KEY(p), could be equal
170 {
171 candidate = p;
174 p = RLINK(p);
175 }
176 }
177 while (p != Node::NullPtr);
178
179 // Optimistic duplicate check: when going right, key >= KEY(candidate)
180 // If also KEY(candidate) >= key (i.e., not less), then key == KEY(candidate)
181 if (candidate != nullptr and not cmp(KEY(candidate), key)) [[unlikely]]
182 {
184 // Truncate stack: remove nodes pushed after candidate
185 const size_t to_pop =
188 if (to_pop > 0)
189 avl_stack.popn(static_cast<int>(to_pop));
190 return candidate;
191 }
192
193 return avl_stack.top();
194 }
195
197 signed char & cmp_result) noexcept
198 {
201
202 Node *p = root;
203 do
204 {
207 avl_stack.push(p);
208 if (cmp(key, KEY(p))) // key < KEY(p)?
209 {
211 p = LLINK(p);
212 }
213 else // key >= KEY(p)
214 {
216 p = RLINK(p);
217 }
218 }
219 while (p != Node::NullPtr);
220
221 return avl_stack.top();
222 }
223
224 // Rotate to left with counter update
225 [[gnu::always_inline]] static Node * rotateLeft(Node *p) noexcept
226 {
227 assert(DIFF(p) == 2);
228 assert(RLINK(p) != Node::NullPtr);
229
230 Node *q = RLINK(p);
231 RLINK(p) = LLINK(q);
232 LLINK(q) = p;
233
234 // Update counters
235 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
236 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
237
238 if (DIFF(q) == 0)
239 {
240 DIFF(q) = -1;
241 DIFF(p) = 1;
242 }
243 else
244 DIFF(q) = DIFF(p) = 0;
245
246 return q;
247 }
248
249 // Rotate to right with counter update
250 [[gnu::always_inline]] static Node * rotateRight(Node *p) noexcept
251 {
252 assert(DIFF(p) == -2);
253 assert(LLINK(p) != Node::NullPtr);
254
255 Node *q = LLINK(p);
256 LLINK(p) = RLINK(q);
257 RLINK(q) = p;
258
259 // Update counters
260 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
261 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
262
263 if (DIFF(q) == 0)
264 {
265 DIFF(q) = 1;
266 DIFF(p) = -1;
267 }
268 else
269 DIFF(q) = DIFF(p) = 0;
270
271 return q;
272 }
273
274 // Double rotate left with counter update
275 [[gnu::always_inline]] static Node * doubleRotateLeft(Node *p) noexcept
276 {
277 assert(DIFF(p) == 2 or DIFF(p) == -2);
278 assert(RLINK(p) != Node::NullPtr and LLINK(RLINK(p)) != Node::NullPtr);
279
280 Node *q = RLINK(p);
281 Node *r = LLINK(q);
282 RLINK(p) = LLINK(r);
283 LLINK(q) = RLINK(r);
284 LLINK(r) = p;
285 RLINK(r) = q;
286
287 // Update counters
288 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
289 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
290 COUNT(r) = COUNT(LLINK(r)) + COUNT(RLINK(r)) + 1;
291
292 unsigned char b, c;
293 if (DIFF(r) == 1)
294 {
295 c = 1;
296 b = 0;
297 }
298 else if (DIFF(r) == -1)
299 {
300 c = 0;
301 b = 1;
302 }
303 else
304 c = b = 1;
305
306 DIFF(r) = 0;
307 DIFF(p) = b - 1;
308 DIFF(q) = 1 - c;
309
310 return r;
311 }
312
313 // Double rotate right with counter update
314 [[gnu::always_inline]]
315 static Node * doubleRotateRight(Node *p) noexcept
316 {
317 assert(DIFF(p) == 2 or DIFF(p) == -2);
318 assert(LLINK(p) != Node::NullPtr and RLINK(LLINK(p)) != Node::NullPtr);
319
320 Node *q = LLINK(p);
321 Node *r = RLINK(q);
322 LLINK(p) = RLINK(r);
323 RLINK(q) = LLINK(r);
324 RLINK(r) = p;
325 LLINK(r) = q;
326
327 // Update counters
328 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
329 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
330 COUNT(r) = COUNT(LLINK(r)) + COUNT(RLINK(r)) + 1;
331
332 unsigned char b, c;
333 if (DIFF(r) == 1)
334 {
335 c = 1;
336 b = 0;
337 }
338 else if (DIFF(r) == -1)
339 {
340 c = 0;
341 b = 1;
342 }
343 else
344 c = b = 1;
345
346 DIFF(r) = 0;
347 DIFF(p) = 1 - c;
348 DIFF(q) = b - 1;
349
350 return r;
351 }
352
357
358 static Rotation_Type rotation_type(Node *p) noexcept
359 {
360 assert(DIFF(p) == 2 or DIFF(p) == -2);
361
362 Node *pc;
363 if (DIFF(p) == 2)
364 {
365 pc = RLINK(p);
366 if (DIFF(pc) == 1 or DIFF(pc) == 0)
367 return ROTATE_LEFT;
368 return DOUBLE_ROTATE_LEFT;
369 }
370
371 pc = LLINK(p);
372 if (DIFF(pc) == -1 or DIFF(pc) == 0)
373 return ROTATE_RIGHT;
374
375 return DOUBLE_ROTATE_RIGHT;
376 }
377
378 static Node * restore_avl(Node *p, Node *pp) noexcept
379 {
380 assert(LLINK(pp) == p or RLINK(pp) == p);
381 assert(DIFF(p) == -2 or DIFF(p) == 2);
382
383 Node **link = LLINK(pp) == p ? &LLINK(pp) : &RLINK(pp);
384 switch (rotation_type(p))
385 {
386 case ROTATE_LEFT: return *link = rotateLeft(p);
387 case ROTATE_RIGHT: return *link = rotateRight(p);
388 case DOUBLE_ROTATE_LEFT: return *link = doubleRotateLeft(p);
389 case DOUBLE_ROTATE_RIGHT: return *link = doubleRotateRight(p);
390 default:
391 AH_ERROR("Invalid rotation type");
392 break;
393 }
394
395 return nullptr;
396 }
397
399 {
400 Node *pp = avl_stack.pop();
401 if (LLINK(pp) == p)
402 --DIFF(pp);
403 else
404 ++DIFF(pp);
405
406 if (DIFF(pp) == 0)
407 {
409 return;
410 }
411
412 if (avl_stack_at_base())
413 return;
414
415 do
416 {
417 Node *gpp = avl_stack.pop();
418 if (LLINK(gpp) == pp)
419 --DIFF(gpp);
420 else
421 ++DIFF(gpp);
422
423 if (DIFF(gpp) == 0)
424 break;
425 if (DIFF(gpp) == -2 or DIFF(gpp) == 2)
426 {
427 Node *ggpp = avl_stack.pop();
429 break;
430 }
431
432 pp = gpp;
433 }
434 while (not avl_stack_at_base());
435
437 }
438
439 Node * swapWithSuccessor(Node *p, Node *& pp) noexcept
440 {
442
443 Node *fSucc = p;
444 Node *succ = RLINK(p);
445
446 avl_stack.push(succ);
447
448 while (LLINK(succ) != Node::NullPtr)
449 {
450 fSucc = succ;
451 succ = LLINK(succ);
452 avl_stack.push(succ);
453 }
454
455 ref_to_stack_top = succ;
456 avl_stack.top() = p;
457
458 if (LLINK(pp) == p)
459 LLINK(pp) = succ;
460 else
461 RLINK(pp) = succ;
462
463 LLINK(succ) = LLINK(p);
464 LLINK(p) = Node::NullPtr;
465
466 if (RLINK(p) == succ)
467 {
468 RLINK(p) = RLINK(succ);
469 RLINK(succ) = p;
470 pp = succ;
471 }
472 else
473 {
474 Node *succr = RLINK(succ);
475 RLINK(succ) = RLINK(p);
476 LLINK(fSucc) = p;
477 RLINK(p) = succr;
478 pp = fSucc;
479 }
480
481 // Swap balance factors
482 DIFF(succ) = DIFF(p);
483
484 // Swap counters
485 COUNT(succ) = COUNT(p);
486
487 return succ;
488 }
489
491 {
492 Node *pp = avl_stack.top(1);
493 Node *ppp = avl_stack.popn(3);
494
495 while (true)
496 {
497 if (left_deficit)
498 ++DIFF(pp);
499 else
500 --DIFF(pp);
501
502 if (DIFF(pp) == -2 or DIFF(pp) == 2)
503 pp = restore_avl(pp, ppp);
504
505 if (DIFF(pp) != 0 or pp == root)
506 break;
507
508 left_deficit = LLINK(ppp) == pp;
509 pp = ppp;
510 ppp = avl_stack.pop();
511 }
512
514 }
515
516 // Update counters along the stack after insertion
518 {
519 // Stack contains: [head_ptr, ..., nodes in path, ..., closest to insertion]
520 // top(0) = closest node, top(size-1) = head_ptr (don't update)
521 const size_t sz = avl_stack.size();
522 for (size_t i = 0; i < sz - 1; ++i)
523 ++COUNT(avl_stack.top(i));
524 }
525
526 // Update counters along the stack after deletion
528 {
529 const size_t sz = avl_stack.size();
530 for (size_t i = 0; i < sz - 1; ++i)
531 --COUNT(avl_stack.top(i));
532 }
533
534 public:
535 using key_type = Key;
536
538 [[nodiscard]] constexpr Compare &key_comp() noexcept { return cmp; }
539
541 [[nodiscard]] constexpr Compare &get_compare() noexcept { return key_comp(); }
542
543 Gen_Avl_Tree_Rk(Compare cmf_fct = Compare()) noexcept
544 : avl_stack(Node::MaxHeight), head_ptr(&head_node),
546 {
548 }
549
555 void swap(Gen_Avl_Tree_Rk & tree) noexcept
556 {
557 std::swap(root, tree.root);
558 std::swap(cmp, tree.cmp);
559 }
560
562
564 [[nodiscard]] constexpr Node *&getRoot() noexcept { return root; }
565
567 [[nodiscard]] constexpr Node * getRoot() const noexcept { return root; }
568
570 [[nodiscard]] size_t size() const noexcept { return COUNT(root); }
571
573 [[nodiscard]] constexpr bool is_empty() const noexcept { return root == Node::NullPtr; }
574
577 [[nodiscard]] Node * search(const Key & key) const noexcept
578 {
580 return result == Node::NullPtr ? nullptr : result;
581 }
582
588 [[nodiscard]] Node * insert(Node *p) noexcept
589 {
590 if (root == Node::NullPtr)
591 return root = p;
592
593 signed char cmp_result = CmpEqual;
595 if (cmp_result == CmpLess)
596 LLINK(pp) = p;
597 else if (cmp_result == CmpGreater)
598 RLINK(pp) = p;
599 else
600 {
602 return nullptr;
603 }
604
607
608 return p;
609 }
610
619 {
620 if (root == Node::NullPtr)
621 return root = p;
622
623 signed char cmp_result = CmpEqual;
625 if (cmp_result == CmpLess)
626 LLINK(pp) = p;
627 else if (cmp_result == CmpGreater)
628 RLINK(pp) = p;
629 else
630 {
632 return pp;
633 }
634
637
638 return p;
639 }
640
642 [[nodiscard]] Node * insert_dup(Node *p) noexcept
643 {
644 if (root == Node::NullPtr)
645 return root = p;
646
647 signed char cmp_result = CmpEqual;
649 if (cmp_result == CmpLess)
650 LLINK(pp) = p;
651 else
652 RLINK(pp) = p;
653
656
657 return p;
658 }
659
662 [[nodiscard]] Node * remove(const Key & key) noexcept
663 {
664 if (root == Node::NullPtr)
665 return nullptr;
666
667 signed char cmp_result = CmpEqual;
669 if (cmp_result != CmpEqual)
670 {
672 return nullptr;
673 }
674
675 Node *pp = avl_stack.top(1);
676 bool left_deficit;
677
678 while (true)
679 {
680 left_deficit = LLINK(pp) == p;
681 if (LLINK(p) == Node::NullPtr)
682 {
683 if (LLINK(pp) == p)
684 LLINK(pp) = RLINK(p);
685 else
686 RLINK(pp) = RLINK(p);
687 break;
688 }
689
690 if (RLINK(p) == Node::NullPtr)
691 {
692 if (LLINK(pp) == p)
693 LLINK(pp) = LLINK(p);
694 else
695 RLINK(pp) = LLINK(p);
696 break;
697 }
698
700 }
701
702 p->reset();
703
704 if (pp == head_ptr)
705 {
707 return p;
708 }
709
712
713 return p;
714 }
715
723 Node * select(const size_t i) const
724 {
725 return Aleph::select(root, i);
726 }
727
734 std::pair<long, Node *> position(const Key & key) const noexcept
735 {
736 std::pair<long, Node *> ret_val;
737
739 inorder_position(root, key, ret_val.second);
740
741 return ret_val;
742 }
743
749 std::pair<long, Node *> find_position(const Key & key) const noexcept
750 {
751 std::pair<long, Node *> r(-2, nullptr);
752
754 find_position(root, key, r.second);
755
756 return r;
757 }
758
761 {
763 }
764
765 private:
766 // Compute height of AVL tree in O(log n) using balance factors
767 static size_t avl_height(Node *p) noexcept
768 {
769 size_t h = 0;
770 while (p != Node::NullPtr)
771 {
772 ++h;
773 // Follow the taller subtree
774 if (DIFF(p) >= 0)
775 p = RLINK(p); // right is taller or equal
776 else
777 p = LLINK(p); // left is taller
778 }
779 return h;
780 }
781
782 // Extract and remove the minimum node from tree rooted at p
783 // Returns the extracted node and updates p to the new root
784 static Node * extract_min(Node *& p) noexcept
785 {
786 if (p == Node::NullPtr)
787 return Node::NullPtr;
788
789 if (LLINK(p) == Node::NullPtr)
790 {
791 Node *ret = p;
792 p = RLINK(p);
793 LLINK(ret) = RLINK(ret) = Node::NullPtr;
794 COUNT(ret) = 1;
795 DIFF(ret) = 0;
796 return ret;
797 }
798
799 // Stack for rebalancing
800 FixedStack<Node **> stack(Node::MaxHeight);
801 Node **pp = &p;
802
803 while (LLINK(*pp) != Node::NullPtr)
804 {
805 stack.push(pp);
806 pp = &LLINK(*pp);
807 }
808
809 Node *ret = *pp;
810 *pp = RLINK(ret);
811
812 // Update counts and rebalance going up
813 while (not stack.is_empty())
814 {
815 Node **parent_ptr = stack.pop();
816 Node *parent = *parent_ptr;
817 --COUNT(parent);
818 ++DIFF(parent); // left subtree got shorter
819
820 if (DIFF(parent) == 2)
821 {
822 // Need to rebalance
823 Node *q = RLINK(parent);
824 if (DIFF(q) >= 0)
825 *parent_ptr = rotateLeft(parent);
826 else
827 *parent_ptr = doubleRotateLeft(parent);
828 }
829 else if (DIFF(parent) == 1)
830 break; // height didn't change
831 }
832
833 LLINK(ret) = RLINK(ret) = Node::NullPtr;
834 COUNT(ret) = 1;
835 DIFF(ret) = 0;
836 return ret;
837 }
838
839 // Extract and remove the maximum node from tree rooted at p
840 static Node * extract_max(Node *& p) noexcept
841 {
842 if (p == Node::NullPtr)
843 return Node::NullPtr;
844
845 if (RLINK(p) == Node::NullPtr)
846 {
847 Node *ret = p;
848 p = LLINK(p);
849 LLINK(ret) = RLINK(ret) = Node::NullPtr;
850 COUNT(ret) = 1;
851 DIFF(ret) = 0;
852 return ret;
853 }
854
855 FixedStack<Node **> stack(Node::MaxHeight);
856 Node **pp = &p;
857
858 while (RLINK(*pp) != Node::NullPtr)
859 {
860 stack.push(pp);
861 pp = &RLINK(*pp);
862 }
863
864 Node *ret = *pp;
865 *pp = LLINK(ret);
866
867 while (not stack.is_empty())
868 {
869 Node **parent_ptr = stack.pop();
870 Node *parent = *parent_ptr;
871 --COUNT(parent);
872 --DIFF(parent); // right subtree got shorter
873
874 if (DIFF(parent) == -2)
875 {
876 Node *q = LLINK(parent);
877 if (DIFF(q) <= 0)
878 *parent_ptr = rotateRight(parent);
879 else
880 *parent_ptr = doubleRotateRight(parent);
881 }
882 else if (DIFF(parent) == -1)
883 break;
884 }
885
886 LLINK(ret) = RLINK(ret) = Node::NullPtr;
887 COUNT(ret) = 1;
888 DIFF(ret) = 0;
889 return ret;
890 }
891
892 // Recursive join of two AVL trees where all keys in t1 < all keys in t2
893 // h1 and h2 are the heights of t1 and t2 respectively
894 static Node * join_exclusive_rec(Node *t1, size_t h1,
895 Node *t2, size_t h2) noexcept
896 {
897 if (t1 == Node::NullPtr)
898 return t2;
899 if (t2 == Node::NullPtr)
900 return t1;
901
902 if (h1 >= h2)
903 {
904 // Extract max from t1 to use as pivot
906 if (t1 != Node::NullPtr)
907 h1 = avl_height(t1);
908 else
909 h1 = 0;
910
911 return join_with_pivot(t1, h1, pivot, t2, h2);
912 }
913 // Extract min from t2 to use as pivot
915 if (t2 != Node::NullPtr)
916 h2 = avl_height(t2);
917 else
918 h2 = 0;
919
920 return join_with_pivot(t1, h1, pivot, t2, h2);
921 }
922
923 // Join t1 and t2 using pivot as the connecting node
924 // All keys in t1 < pivot < all keys in t2
925 static Node * join_with_pivot(Node *t1, const size_t h1, Node *pivot,
926 Node *t2, const size_t h2) noexcept
927 {
928 if (h1 <= h2 + 1 and h2 <= h1 + 1)
929 {
930 // Heights are close enough, pivot becomes root
931 LLINK(pivot) = t1;
932 RLINK(pivot) = t2;
933 DIFF(pivot) = static_cast<signed char>(h2) - static_cast<signed char>(h1);
934 COUNT(pivot) = COUNT(t1) + COUNT(t2) + 1;
935 return pivot;
936 }
937
938 if (h1 > h2)
939 {
940 // t1 is taller, descend into right spine of t1
941 Node *result = join_right(t1, h1, pivot, t2, h2);
942 return result;
943 }
944 // t2 is taller, descend into left spine of t2
945 Node *result = join_left(t1, h1, pivot, t2, h2);
946 return result;
947 }
948
949 // Join when h1 > h2 + 1: descend right spine of t1
950 static Node * join_right(Node *t1, const size_t h1, Node *pivot,
951 Node *t2, const size_t h2) noexcept
952 {
953 FixedStack<Node **> stack(Node::MaxHeight);
954 Node **pp = &t1;
955 size_t curr_h = h1;
956
957 // Descend right spine until we find a subtree of appropriate height
958 while (curr_h > h2 + 1 and *pp != Node::NullPtr)
959 {
960 stack.push(pp);
961 if (DIFF(*pp) >= 0)
962 curr_h--; // right child has height curr_h - 1
963 else
964 curr_h -= 2; // right child has height curr_h - 2 (since left is curr_h - 1)
965
966 pp = &RLINK(*pp);
967 }
968
969 // Now *pp points to a subtree of height <= h2 + 1
970 // Join pivot with *pp and t2
971 LLINK(pivot) = *pp;
972 RLINK(pivot) = t2;
973 const size_t left_h = (*pp != Node::NullPtr) ? avl_height(*pp) : 0;
974 DIFF(pivot) = static_cast<signed char>(h2) - static_cast<signed char>(left_h);
975 COUNT(pivot) = COUNT(*pp) + COUNT(t2) + 1;
976 *pp = pivot;
977
978 // Rebalance going up
979 while (not stack.is_empty())
980 {
981 Node **parent_ptr = stack.pop();
982 Node *parent = *parent_ptr;
983 COUNT(parent) = COUNT(LLINK(parent)) + COUNT(RLINK(parent)) + 1;
984
985 const size_t new_right_h = avl_height(RLINK(parent));
986 const size_t new_left_h = avl_height(LLINK(parent));
987 DIFF(parent) = static_cast<signed char>(new_right_h) -
988 static_cast<signed char>(new_left_h);
989
990 if (DIFF(parent) == 2)
991 {
992 if (Node *q = RLINK(parent); DIFF(q) >= 0)
993 *parent_ptr = rotateLeft(parent);
994 else
995 *parent_ptr = doubleRotateLeft(parent);
996 }
997 }
998
999 return t1;
1000 }
1001
1002 // Join when h2 > h1 + 1: descend left spine of t2
1003 static Node * join_left(Node *t1, const size_t h1, Node *pivot,
1004 Node *t2, const size_t h2) noexcept
1005 {
1006 FixedStack<Node **> stack(Node::MaxHeight);
1007 Node **pp = &t2;
1008 size_t curr_h = h2;
1009
1010 while (curr_h > h1 + 1 and *pp != Node::NullPtr)
1011 {
1012 stack.push(pp);
1013 if (DIFF(*pp) <= 0)
1014 curr_h--;
1015 else
1016 curr_h -= 2;
1017
1018 pp = &LLINK(*pp);
1019 }
1020
1021 RLINK(pivot) = *pp;
1022 LLINK(pivot) = t1;
1023 const size_t right_h = (*pp != Node::NullPtr) ? avl_height(*pp) : 0;
1024 DIFF(pivot) = static_cast<signed char>(right_h) - static_cast<signed char>(h1);
1025 COUNT(pivot) = COUNT(t1) + COUNT(*pp) + 1;
1026 *pp = pivot;
1027
1028 while (not stack.is_empty())
1029 {
1030 Node **parent_ptr = stack.pop();
1031 Node *parent = *parent_ptr;
1032 COUNT(parent) = COUNT(LLINK(parent)) + COUNT(RLINK(parent)) + 1;
1033
1034 const size_t new_right_h = avl_height(RLINK(parent));
1035 const size_t new_left_h = avl_height(LLINK(parent));
1036 DIFF(parent) = static_cast<signed char>(new_right_h) -
1037 static_cast<signed char>(new_left_h);
1038
1039 if (DIFF(parent) == -2)
1040 {
1041 if (Node *q = LLINK(parent); DIFF(q) <= 0)
1042 *parent_ptr = rotateRight(parent);
1043 else
1044 *parent_ptr = doubleRotateRight(parent);
1045 }
1046 }
1047
1048 return t2;
1049 }
1050
1051 // Split by key recursively
1052 // Returns the node containing key (or NullPtr if not found)
1053 // t1 gets all keys < key, t2 gets all keys > key
1054 Node * split_key_rec(Node *p, const Key & key,
1055 Node *& t1, Node *& t2) noexcept
1056 {
1057 if (p == Node::NullPtr)
1058 {
1059 t1 = t2 = Node::NullPtr;
1060 return Node::NullPtr;
1061 }
1062
1063 Node *found;
1064 if (cmp(key, KEY(p)))
1065 {
1066 // key < p->key, go left
1067 Node *left_t2;
1068 found = split_key_rec(LLINK(p), key, t1, left_t2);
1069
1070 // p and its right subtree go to t2
1071 LLINK(p) = Node::NullPtr;
1072 const size_t left_t2_h = (left_t2 != Node::NullPtr) ? avl_height(left_t2) : 0;
1073 const size_t right_h = (RLINK(p) != Node::NullPtr) ? avl_height(RLINK(p)) : 0;
1074
1075 Node *right_tree = RLINK(p);
1076 RLINK(p) = Node::NullPtr;
1077 COUNT(p) = 1;
1078 DIFF(p) = 0;
1079
1081 }
1082 else if (cmp(KEY(p), key))
1083 {
1084 // key > p->key, go right
1085 Node *right_t1;
1086 found = split_key_rec(RLINK(p), key, right_t1, t2);
1087
1088 // p and its left subtree go to t1
1089 RLINK(p) = Node::NullPtr;
1090 const size_t right_t1_h = (right_t1 != Node::NullPtr) ? avl_height(right_t1) : 0;
1091 const size_t left_h = (LLINK(p) != Node::NullPtr) ? avl_height(LLINK(p)) : 0;
1092
1093 Node *left_tree = LLINK(p);
1094 LLINK(p) = Node::NullPtr;
1095 COUNT(p) = 1;
1096 DIFF(p) = 0;
1097
1099 }
1100 else
1101 {
1102 // Found the key
1103 t1 = LLINK(p);
1104 t2 = RLINK(p);
1105 LLINK(p) = RLINK(p) = Node::NullPtr;
1106 COUNT(p) = 1;
1107 DIFF(p) = 0;
1108 found = p;
1109 }
1110
1111 return found;
1112 }
1113
1114 // Split by key for duplicates: keys <= key go to t1, keys > key go to t2
1115 void split_key_dup_rec(Node *p, const Key & key,
1116 Node *& t1, Node *& t2) noexcept
1117 {
1118 if (p == Node::NullPtr)
1119 {
1120 t1 = t2 = Node::NullPtr;
1121 return;
1122 }
1123
1124 if (cmp(key, KEY(p)))
1125 {
1126 // key < p->key, p goes to t2
1127 Node *left_t2;
1128 split_key_dup_rec(LLINK(p), key, t1, left_t2);
1129
1130 LLINK(p) = Node::NullPtr;
1131 const size_t left_t2_h = (left_t2 != Node::NullPtr) ? avl_height(left_t2) : 0;
1132 const size_t right_h = (RLINK(p) != Node::NullPtr) ? avl_height(RLINK(p)) : 0;
1133
1134 Node *right_tree = RLINK(p);
1135 RLINK(p) = Node::NullPtr;
1136 COUNT(p) = 1;
1137 DIFF(p) = 0;
1138
1140 }
1141 else
1142 {
1143 // key >= p->key, p goes to t1
1144 Node *right_t1;
1146
1147 RLINK(p) = Node::NullPtr;
1148 const size_t right_t1_h = (right_t1 != Node::NullPtr) ? avl_height(right_t1) : 0;
1149 const size_t left_h = (LLINK(p) != Node::NullPtr) ? avl_height(LLINK(p)) : 0;
1150
1151 Node *left_tree = LLINK(p);
1152 LLINK(p) = Node::NullPtr;
1153 COUNT(p) = 1;
1154 DIFF(p) = 0;
1155
1157 }
1158 }
1159
1160 // Split by position recursively
1161 // Nodes with position < pos go to t1, nodes with position >= pos go to t2
1162 void split_pos_rec(Node *p, size_t pos, Node *& t1, Node *& t2) noexcept
1163 {
1164 if (p == Node::NullPtr)
1165 {
1166 t1 = t2 = Node::NullPtr;
1167 return;
1168 }
1169
1170 if (const size_t left_count = COUNT(LLINK(p)); pos <= left_count)
1171 {
1172 // Split point is in left subtree or at p
1173 Node *left_t2;
1174 split_pos_rec(LLINK(p), pos, t1, left_t2);
1175
1176 // p goes to t2
1177 LLINK(p) = Node::NullPtr;
1178 const size_t left_t2_h = (left_t2 != Node::NullPtr) ? avl_height(left_t2) : 0;
1179 const size_t right_h = (RLINK(p) != Node::NullPtr) ? avl_height(RLINK(p)) : 0;
1180
1181 Node *right_tree = RLINK(p);
1182 RLINK(p) = Node::NullPtr;
1183 COUNT(p) = 1;
1184 DIFF(p) = 0;
1185
1187 }
1188 else
1189 {
1190 // Split point is in right subtree
1191 Node *right_t1;
1192 split_pos_rec(RLINK(p), pos - left_count - 1, right_t1, t2);
1193
1194 // p goes to t1
1195 RLINK(p) = Node::NullPtr;
1196 const size_t right_t1_h = (right_t1 != Node::NullPtr) ? avl_height(right_t1) : 0;
1197 const size_t left_h = (LLINK(p) != Node::NullPtr) ? avl_height(LLINK(p)) : 0;
1198
1199 Node *left_tree = LLINK(p);
1200 LLINK(p) = Node::NullPtr;
1201 COUNT(p) = 1;
1202 DIFF(p) = 0;
1203
1205 }
1206 }
1207
1208 public:
1218 {
1219 if (t.root == Node::NullPtr)
1220 return;
1221
1222 if (root == Node::NullPtr)
1223 {
1224 root = t.root;
1225 t.root = Node::NullPtr;
1226 return;
1227 }
1228
1229 // Collect nodes from t in preorder and insert them one by one
1230 // This is O(m log(n+m)) but guarantees correctness
1231 FixedStack<Node *> stack(Node::MaxHeight);
1232 stack.push(t.root);
1233 t.root = Node::NullPtr;
1234
1235 while (not stack.is_empty())
1236 {
1237 Node *p = stack.pop();
1238 Node *left = LLINK(p);
1239 Node *right = RLINK(p);
1240
1241 // Reset node and insert
1242 LLINK(p) = RLINK(p) = Node::NullPtr;
1243 COUNT(p) = 1;
1244 DIFF(p) = 0;
1245 (void)insert(p);
1246
1247 if (right != Node::NullPtr)
1248 stack.push(right);
1249 if (left != Node::NullPtr)
1250 stack.push(left);
1251 }
1252 }
1253
1267 Node * split_key(const Key & key, Gen_Avl_Tree_Rk & t1,
1268 Gen_Avl_Tree_Rk & t2) noexcept
1269 {
1270 if (root == Node::NullPtr)
1271 return nullptr;
1272
1273 // Simple O(n) implementation: iterate through tree and partition
1274 Node *found = nullptr;
1275 FixedStack<Node *> stack(Node::MaxHeight);
1276 stack.push(root);
1277 root = Node::NullPtr;
1278
1279 while (not stack.is_empty())
1280 {
1281 Node *p = stack.pop();
1282 Node *left = LLINK(p);
1283 Node *right = RLINK(p);
1284
1285 if (right != Node::NullPtr)
1286 stack.push(right);
1287 if (left != Node::NullPtr)
1288 stack.push(left);
1289
1290 LLINK(p) = RLINK(p) = Node::NullPtr;
1291 COUNT(p) = 1;
1292 DIFF(p) = 0;
1293
1294 if (cmp(KEY(p), key))
1295 (void)t1.insert(p);
1296 else if (cmp(key, KEY(p)))
1297 (void)t2.insert(p);
1298 else
1299 found = p; // Found the key
1300 }
1301
1302 return found;
1303 }
1304
1317 void split_key_dup(const Key & key, Gen_Avl_Tree_Rk & t1,
1318 Gen_Avl_Tree_Rk & t2) noexcept
1319 {
1320 if (root == Node::NullPtr)
1321 return;
1322
1323 FixedStack<Node *> stack(Node::MaxHeight);
1324 stack.push(root);
1325 root = Node::NullPtr;
1326
1327 while (not stack.is_empty())
1328 {
1329 Node *p = stack.pop();
1330 Node *left = LLINK(p);
1331 Node *right = RLINK(p);
1332
1333 if (right != Node::NullPtr)
1334 stack.push(right);
1335 if (left != Node::NullPtr)
1336 stack.push(left);
1337
1338 LLINK(p) = RLINK(p) = Node::NullPtr;
1339 COUNT(p) = 1;
1340 DIFF(p) = 0;
1341
1342 if (cmp(key, KEY(p)))
1343 (void)t2.insert(p);
1344 else
1345 (void)t1.insert_dup(p);
1346 }
1347 }
1348
1361 void split_pos(const size_t pos, Gen_Avl_Tree_Rk & t1,
1362 Gen_Avl_Tree_Rk & t2) noexcept
1363 {
1364 if (root == Node::NullPtr)
1365 return;
1366
1367 if (pos == 0)
1368 {
1369 t2.root = root;
1370 root = Node::NullPtr;
1371 return;
1372 }
1373
1374 if (pos >= size())
1375 {
1376 t1.root = root;
1377 root = Node::NullPtr;
1378 return;
1379 }
1380
1381 // Simple O(n) implementation using inorder traversal
1382 size_t count = 0;
1383 FixedStack<Node *> stack(Node::MaxHeight);
1384 Node *curr = root;
1385 root = Node::NullPtr;
1386
1387 // Inorder traversal
1388 while (curr != Node::NullPtr or not stack.is_empty())
1389 {
1390 while (curr != Node::NullPtr)
1391 {
1392 stack.push(curr);
1393 Node *left = LLINK(curr);
1394 LLINK(curr) = Node::NullPtr; // Disconnect
1395 curr = left;
1396 }
1397
1398 curr = stack.pop();
1399 Node *right = RLINK(curr);
1400 RLINK(curr) = Node::NullPtr;
1401 COUNT(curr) = 1;
1402 DIFF(curr) = 0;
1403
1404 if (count < pos)
1405 (void)t1.insert(curr);
1406 else
1407 (void)t2.insert(curr);
1408
1409 ++count;
1410 curr = right;
1411 }
1412 }
1413
1422 class Iterator : public BinTreeXt_Iterator<Gen_Avl_Tree_Rk, Node, Key, Compare>
1423 {
1425
1426 public:
1427 using Base::Base;
1428 using Base::operator=;
1429 }; // end class Iterator
1430 };
1431
1432
1442 template <typename Key, class Compare = Aleph::less<Key>>
1444 struct Avl_Tree_Rk : public Gen_Avl_Tree_Rk<AvlNodeRk, Key, Compare>
1445 {
1447 using Base::Base;
1448 };
1449
1450
1460 template <typename Key, class Compare = Aleph::less<Key>>
1462 struct Avl_Tree_Rk_Vtl : public Gen_Avl_Tree_Rk<AvlNodeRkVtl, Key, Compare>
1463 {
1465 using Base::Base;
1466 };
1467} // end namespace Aleph
1468
1469# endif // TPL_AVLRK_H
C++20 concepts for constraining comparison functors.
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.
Fixed length stack.
T & base() noexcept
Return the internal array base.
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 pop() noexcept
Pop by moving the top of stack.
T & top() noexcept
Return a modifiable reference to stack's top.
void empty() noexcept
Empty the stack.
T & push(const T &data) noexcept(std::is_nothrow_copy_assignable_v< T >)
Push a copy of data
Iterator over the nodes.
Definition tpl_avlRk.H:1423
AVL balanced binary search tree with rank (order statistics).
Definition tpl_avlRk.H:113
Node * insert(Node *p) noexcept
Insert the node pointed by p in the tree.
Definition tpl_avlRk.H:588
void split_key_dup_rec(Node *p, const Key &key, Node *&t1, Node *&t2) noexcept
Definition tpl_avlRk.H:1115
static Node * join_with_pivot(Node *t1, const size_t h1, Node *pivot, Node *t2, const size_t h2) noexcept
Definition tpl_avlRk.H:925
constexpr Compare & key_comp() noexcept
The key type.
Definition tpl_avlRk.H:538
NodeType< Key > Node
Definition tpl_avlRk.H:115
Node * search_and_stack_avl(const Key &key, signed char &cmp_result) noexcept
Definition tpl_avlRk.H:150
static size_t avl_height(Node *p) noexcept
Definition tpl_avlRk.H:767
constexpr Node *& getRoot() noexcept
Return a modifiable reference to tree's root.
Definition tpl_avlRk.H:564
bool avl_stack_at_base() noexcept
Definition tpl_avlRk.H:124
static Node * join_exclusive_rec(Node *t1, size_t h1, Node *t2, size_t h2) noexcept
Definition tpl_avlRk.H:894
Gen_Avl_Tree_Rk(Compare cmf_fct=Compare()) noexcept
Definition tpl_avlRk.H:543
Node * select(const size_t i) const
Return the i-th node in order sense.
Definition tpl_avlRk.H:723
Node * search_dup_and_stack_avl(const Key &key, signed char &cmp_result) noexcept
Definition tpl_avlRk.H:196
void update_counters_after_insertion() noexcept
Definition tpl_avlRk.H:517
static Node * join_left(Node *t1, const size_t h1, Node *pivot, Node *t2, const size_t h2) noexcept
Definition tpl_avlRk.H:1003
Node * search_or_insert(Node *p) noexcept
Search or insert a key.
Definition tpl_avlRk.H:618
static Rotation_Type rotation_type(Node *p) noexcept
Definition tpl_avlRk.H:358
void restore_avl_after_insertion(Node *p) noexcept
Definition tpl_avlRk.H:398
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:749
Node * split_key_rec(Node *p, const Key &key, Node *&t1, Node *&t2) noexcept
Definition tpl_avlRk.H:1054
Node * remove(const Key &key) noexcept
Remove from tree the node containing key.
Definition tpl_avlRk.H:662
static Node * restore_avl(Node *p, Node *pp) noexcept
Definition tpl_avlRk.H:378
static Node * rotateLeft(Node *p) noexcept
Definition tpl_avlRk.H:225
size_t size() const noexcept
Return the number of nodes in the tree.
Definition tpl_avlRk.H:570
void split_pos_rec(Node *p, size_t pos, Node *&t1, Node *&t2) noexcept
Definition tpl_avlRk.H:1162
static Node * extract_max(Node *&p) noexcept
Definition tpl_avlRk.H:840
virtual ~Gen_Avl_Tree_Rk() noexcept
Definition tpl_avlRk.H:561
static Node * extract_min(Node *&p) noexcept
Definition tpl_avlRk.H:784
static Node * rotateRight(Node *p) noexcept
Definition tpl_avlRk.H:250
void join_exclusive(Gen_Avl_Tree_Rk &t) noexcept
Join this tree exclusively with another tree.
Definition tpl_avlRk.H:1217
Node * swapWithSuccessor(Node *p, Node *&pp) noexcept
Definition tpl_avlRk.H:439
constexpr bool is_empty() const noexcept
Return true if tree is empty.
Definition tpl_avlRk.H:573
static Node * doubleRotateLeft(Node *p) noexcept
Definition tpl_avlRk.H:275
constexpr Compare & get_compare() noexcept
Definition tpl_avlRk.H:541
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:555
Node * insert_dup(Node *p) noexcept
Insert the node p without testing for key duplicity.
Definition tpl_avlRk.H:642
void restore_avl_after_deletion(bool left_deficit) noexcept
Definition tpl_avlRk.H:490
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:1317
static Node * doubleRotateRight(Node *p) noexcept
Definition tpl_avlRk.H:315
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:1267
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:1361
constexpr Node * getRoot() const noexcept
Return a pointer to the tree's root.
Definition tpl_avlRk.H:567
bool verify() const noexcept
Return true if the tree is a valid AVL tree with correct counters.
Definition tpl_avlRk.H:760
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:577
void update_counters_after_deletion() noexcept
Definition tpl_avlRk.H:527
void clean_avl_stack() noexcept
Definition tpl_avlRk.H:131
FixedStack< Node * > avl_stack
The type of node.
Definition tpl_avlRk.H:118
std::pair< long, Node * > position(const Key &key) const noexcept
Compute the inorder position of a key.
Definition tpl_avlRk.H:734
static Node * join_right(Node *t1, const size_t h1, Node *pivot, Node *t2, const size_t h2) noexcept
Definition tpl_avlRk.H:950
Strict weak ordering constraint for BST comparators.
Definition ah-concepts.H:84
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.
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.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
bool is_avl_rk(Node *p)
Verify if tree rooted at p is a valid AVL tree with correct counters.
Definition avlNodeRk.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.
@ CmpGreater
First argument is greater than second.
@ CmpLess
First argument is less than second.
@ CmpEqual
Arguments are equal.
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:1463
AVL binary search tree with nodes without virtual destructor and with subtree counters for select/pos...
Definition tpl_avlRk.H:1445
#define RLINK(i, n)
#define LLINK(i, n)
gsl_rng * r
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).