Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_rbRk.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_RBRK_H
51# define TPL_RBRK_H
52
53# include <ahFunction.H>
54# include <tpl_arrayStack.H>
55# include <tpl_binNodeUtils.H>
56# include <tpl_binNodeXt.H>
57# include <tpl_binTreeOps.H>
58# include <rbNodeRk.H>
59# include <ah-errors.H>
60
61namespace Aleph {
62
106template <template <typename> class NodeType, typename Key, class Compare>
108{
109public:
110
112
113private:
114
119 Compare cmp;
120 static constexpr signed char CmpLess = -1;
121 static constexpr signed char CmpEqual = 0;
122 static constexpr signed char CmpGreater = 1;
123
125 Node * search_and_stack_rb(const Key & key,
126 signed char & cmp_result) noexcept
127 {
128 Node *p = root;
129 Node *candidate = nullptr; // Tracks potential duplicate when going right
130 size_t candidate_pos = 0; // Stack size when candidate was set
131
133 do
134 {
135 rb_stack.push(p);
136 if (cmp(key, KEY(p))) // key < KEY(p)
137 {
139 p = LLINK(p);
140 }
141 else // key >= KEY(p), could be equal
142 {
143 candidate = p;
146 p = RLINK(p);
147 }
148 }
149 while (p != Node::NullPtr);
150
151 // Optimistic duplicate check: when going right, key >= KEY(candidate)
152 // If also KEY(candidate) >= key (i.e., not less), then key == KEY(candidate)
153 if (candidate != nullptr and not cmp(KEY(candidate), key)) [[unlikely]]
154 {
156 // Truncate stack: remove nodes pushed after candidate
158 return candidate;
159 }
160
161 return rb_stack.top();
162 }
163
164 Node * search_dup_and_stack_rb(const Key & key,
165 signed char & cmp_result)
166 {
167 Node * p = root;
170 do
171 {
172 rb_stack.push(p);
173 const Key & pk = KEY(p);
174 if (cmp(key, pk))
175 {
177 p = LLINK(p);
178 }
179 else
180 {
182 p = RLINK(p);
183 }
184 }
185 while (p != Node::NullPtr);
186
187 return rb_stack.top();
188 }
189
190 // Rotate to right with counter update
191 Node * rotate_to_right_rk(Node * p, Node * pp) noexcept
192 {
193 assert(p != Node::NullPtr);
194 assert(pp != Node::NullPtr);
195 assert(LLINK(pp) == p or RLINK(pp) == p);
196
197 Node * q = LLINK(p);
198 LLINK(p) = RLINK(q);
199 RLINK(q) = p;
200
201 // Update counters
202 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
203 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
204
205 if (LLINK(pp) == p)
206 LLINK(pp) = q;
207 else
208 RLINK(pp) = q;
209
210 return q;
211 }
212
213 // Rotate to left with counter update
214 Node * rotate_to_left_rk(Node * p, Node * pp) noexcept
215 {
216 assert(p != Node::NullPtr);
217 assert(pp != Node::NullPtr);
218 assert(LLINK(pp) == p or RLINK(pp) == p);
219
220 Node * q = RLINK(p);
221 RLINK(p) = LLINK(q);
222 LLINK(q) = p;
223
224 // Update counters
225 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
226 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
227
228 if (LLINK(pp) == p)
229 LLINK(pp) = q;
230 else
231 RLINK(pp) = q;
232
233 return q;
234 }
235
237 {
238 assert(COLOR(p) == RED);
239
240 while (p != root)
241 {
242 Node * pp = rb_stack.pop();
243 if (COLOR(pp) == BLACK)
244 break;
245
246 if (root == pp)
247 {
248 COLOR(root) = BLACK;
249 break;
250 }
251
252 Node * ppp = rb_stack.pop();
253 Node * spp = LLINK(ppp) == pp ? RLINK(ppp) : LLINK(ppp);
254
255 if (COLOR(spp) == RED)
256 {
257 COLOR(ppp) = RED;
258 COLOR(pp) = BLACK;
259 COLOR(spp) = BLACK;
260 p = ppp;
261 continue;
262 }
263
264 Node * pppp = rb_stack.pop();
265 if (LLINK(pp) == p and LLINK(ppp) == pp)
266 {
268 COLOR(pp) = BLACK;
269 }
270 else if (RLINK(pp) == p and RLINK(ppp) == pp)
271 {
273 COLOR(pp) = BLACK;
274 }
275 else
276 {
277 if (RLINK(pp) == p)
278 {
281 }
282 else
283 {
286 }
287 COLOR(p) = BLACK;
288 }
289
290 COLOR(ppp) = RED;
291 break;
292 }
293
294 rb_stack.empty();
295 }
296
298 {
300
301 Node * fSucc = p;
302 Node * succ = RLINK(p);
303 rb_stack.push(succ);
304
305 while (LLINK(succ) != Node::NullPtr)
306 {
307 fSucc = succ;
308 succ = LLINK(succ);
309 rb_stack.push(succ);
310 }
311
312 ref_rb_stack = succ;
313 rb_stack.top() = p;
314
315 if (LLINK(pp) == p)
316 LLINK(pp) = succ;
317 else
318 RLINK(pp) = succ;
319
320 LLINK(succ) = LLINK(p);
321 LLINK(p) = Node::NullPtr;
322
323 if (RLINK(p) == succ)
324 {
325 RLINK(p) = RLINK(succ);
326 RLINK(succ) = p;
327 pp = succ;
328 }
329 else
330 {
331 Node * succr = RLINK(succ);
332 RLINK(succ) = RLINK(p);
333 LLINK(fSucc) = p;
334 RLINK(p) = succr;
335 pp = fSucc;
336 }
337
338 std::swap(COLOR(succ), COLOR(p));
339 COUNT(succ) = COUNT(p); // Copy counter to successor position
340 }
341
343 {
344 if (COLOR(p) == RED)
345 {
346 COLOR(p) = BLACK;
347 return;
348 }
349
350 Node * pp = rb_stack.popn(2);
351 while (p != root)
352 {
353 assert(LLINK(pp) == p or RLINK(pp) == p);
355
356 Node * sp = LLINK(pp) == p ? RLINK(pp) : LLINK(pp);
357 if (COLOR(sp) == RED)
358 {
359 Node *& ppp = rb_stack.top();
360
361 if (LLINK(pp) == p)
362 {
363 sp = LLINK(sp);
365 }
366 else
367 {
368 sp = RLINK(sp);
370 }
371
372 COLOR(ppp) = BLACK;
373 COLOR(pp) = RED;
374 }
375
376 Node * np, * snp;
377 if (LLINK(pp) == p)
378 {
379 np = RLINK(sp);
380 snp = LLINK(sp);
381 }
382 else
383 {
384 np = LLINK(sp);
385 snp = RLINK(sp);
386 }
387
388 if (COLOR(np) == RED)
389 {
390 Node * ppp = rb_stack.top();
391
392 if (RLINK(sp) == np)
394 else
396
397 COLOR(sp) = COLOR(pp);
398 COLOR(pp) = BLACK;
399 COLOR(np) = BLACK;
400
401 return;
402 }
403
404 if (COLOR(snp) == RED)
405 {
406 Node * ppp = rb_stack.top();
407
408 if (LLINK(sp) == snp)
409 {
412 }
413 else
414 {
417 }
418
419 COLOR(snp) = COLOR(pp);
420 COLOR(pp) = BLACK;
421
422 return;
423 }
424
425 if (COLOR(pp) == RED)
426 {
427 COLOR(pp) = BLACK;
428 COLOR(sp) = RED;
429 return;
430 }
431
432 COLOR(sp) = RED;
433 p = pp;
434 pp = rb_stack.pop();
435 }
436 }
437
438 // Update counters along the stack after insertion
440 {
441 // Stack contains: [head, ..., nodes in path, ..., closest to insertion]
442 // top(0) = closest node, top(size-1) = head (don't update)
443 const size_t sz = rb_stack.size();
444 for (size_t i = 0; i < sz - 1; ++i)
445 ++COUNT(rb_stack.top(i));
446 }
447
448 // Update counters along the stack after deletion
450 {
451 const size_t sz = rb_stack.size();
452 for (size_t i = 0; i < sz - 1; ++i)
453 --COUNT(rb_stack.top(i));
454 }
455
456public:
457
458 typedef Key key_type;
459
460 Compare & key_comp() noexcept { return cmp; }
461
462 Compare & get_compare() noexcept { return key_comp(); }
463
464 Gen_Rb_Tree_Rk(Compare cmp_arg = Compare())
465 : head(&head_node), root(head_node.getR()),
466 rb_stack(Node::MaxHeight), cmp(cmp_arg)
467 { /* empty */ }
468
469 void swap(Gen_Rb_Tree_Rk & tree) noexcept
470 {
471 std::swap(root, tree.root);
472 std::swap(cmp, tree.cmp);
473 }
474
476 : head(&head_node), root(head_node.getR()),
477 rb_stack(Node::MaxHeight), cmp(std::move(tree.cmp))
478 {
479 root = tree.root;
480 tree.root = Node::NullPtr;
481 }
482
484 {
485 if (this != &tree)
486 {
487 root = tree.root;
488 tree.root = Node::NullPtr;
489 cmp = std::move(tree.cmp);
490 }
491 return *this;
492 }
493
494 virtual ~Gen_Rb_Tree_Rk() = default;
495
496 Node * search(const Key & key)
497 {
499 return retVal == Node::NullPtr ? nullptr : retVal;
500 }
501
502 Node *& getRoot() noexcept { return root; }
503
504 [[nodiscard]] bool is_empty() const noexcept { return root == Node::NullPtr; }
505
506 [[nodiscard]] size_t size() const noexcept { return COUNT(root); }
507
509 {
510 assert(p != nullptr and p != Node::NullPtr);
511 assert(COLOR(p) == RED);
512
513 if (root == Node::NullPtr)
514 return root = p;
515
516 signed char cmp_result = CmpEqual;
518 if (cmp_result == CmpLess)
519 LLINK(q) = p;
520 else if (cmp_result == CmpGreater)
521 RLINK(q) = p;
522 else
523 {
524 rb_stack.empty();
525 return nullptr;
526 }
527
530
531 return p;
532 }
533
535 {
536 assert(p != nullptr and p != Node::NullPtr);
537 assert(COLOR(p) == RED);
538
539 if (root == Node::NullPtr)
540 return root = p;
541
542 signed char cmp_result = CmpEqual;
544 if (cmp_result == CmpLess)
545 LLINK(q) = p;
546 else if (cmp_result == CmpGreater)
547 RLINK(q) = p;
548 else
549 {
550 rb_stack.empty();
551 return q;
552 }
553
556
557 return p;
558 }
559
561 {
562 assert(p != nullptr and p != Node::NullPtr);
563 assert(COLOR(p) == RED);
564
565 if (root == Node::NullPtr)
566 return root = p;
567
568 signed char cmp_result = CmpEqual;
570 if (cmp_result == CmpLess)
571 LLINK(q) = p;
572 else
573 RLINK(q) = p;
574
577
578 return p;
579 }
580
582
583 Node * remove(const Key & key)
584 {
585 if (root == Node::NullPtr)
586 return nullptr;
587
588 signed char cmp_result = CmpEqual;
590 if (cmp_result != CmpEqual)
591 {
592 rb_stack.empty();
593 return nullptr;
594 }
595
596 Node * pq = rb_stack.top(1);
597 Node * p;
598
599 while (true)
600 {
601 if (LLINK(q) == Node::NullPtr)
602 {
603 if (LLINK(pq) == q)
604 p = LLINK(pq) = RLINK(q);
605 else
606 p = RLINK(pq) = RLINK(q);
607 break;
608 }
609
610 if (RLINK(q) == Node::NullPtr)
611 {
612 if (LLINK(pq) == q)
613 p = LLINK(pq) = LLINK(q);
614 else
615 p = RLINK(pq) = LLINK(q);
616 break;
617 }
618
620 }
621
623
624 if (COLOR(q) == BLACK)
626
627 q->reset();
628 rb_stack.empty();
629
630 return q;
631 }
632
640 Node * select(const size_t i) const
641 {
642 return Aleph::select(root, i);
643 }
644
651 std::pair<long, Node*> position(const Key & key) const noexcept
652 {
653 std::pair<long, Node*> ret_val;
654
656 inorder_position(root, key, ret_val.second);
657
658 return ret_val;
659 }
660
666 std::pair<long, Node*> find_position(const Key & key) const noexcept
667 {
668 std::pair<long, Node*> r(-2, nullptr);
669
671 find_position(root, key, r.second);
672
673 return r;
674 }
675
676private:
677
678 // Compute black height of RB tree (count black nodes to any leaf)
679 static size_t black_height(Node * p) noexcept
680 {
681 size_t h = 0;
682 while (p != Node::NullPtr)
683 {
684 if (COLOR(p) == BLACK)
685 ++h;
686 p = LLINK(p); // Any path works since all paths have same black height
687 }
688 return h;
689 }
690
691 // Simple rotation without parent link update (for internal use)
692 static Node * rotate_right_simple(Node * p) noexcept
693 {
694 Node * q = LLINK(p);
695 LLINK(p) = RLINK(q);
696 RLINK(q) = p;
697 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
698 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
699 return q;
700 }
701
702 static Node * rotate_left_simple(Node * p) noexcept
703 {
704 Node * q = RLINK(p);
705 RLINK(p) = LLINK(q);
706 LLINK(q) = p;
707 COUNT(p) = COUNT(LLINK(p)) + COUNT(RLINK(p)) + 1;
708 COUNT(q) = COUNT(LLINK(q)) + COUNT(RLINK(q)) + 1;
709 return q;
710 }
711
712 // Fix red-red violation going up from node p
713 // pp_ptr is a pointer to the pointer that points to the subtree being fixed
714 static void fix_red_violation(Node *& subtree_root) noexcept
715 {
716 // Simplified iterative fix for red-red violations
717 // This version uses recursion-based fixing during join
718 if (subtree_root == Node::NullPtr)
719 return;
720
721 // Check left child for red-red
722 if (LLINK(subtree_root) != Node::NullPtr and
724 {
726 if (LLINK(l) != Node::NullPtr and COLOR(LLINK(l)) == RED)
727 {
728 // Left-left case
732 return;
733 }
734 if (RLINK(l) != Node::NullPtr and COLOR(RLINK(l)) == RED)
735 {
736 // Left-right case
741 return;
742 }
743 }
744
745 // Check right child for red-red
746 if (RLINK(subtree_root) != Node::NullPtr and
748 {
749 Node * r = RLINK(subtree_root);
750 if (RLINK(r) != Node::NullPtr and COLOR(RLINK(r)) == RED)
751 {
752 // Right-right case
756 return;
757 }
758 if (LLINK(r) != Node::NullPtr and COLOR(LLINK(r)) == RED)
759 {
760 // Right-left case
765 return;
766 }
767 }
768 }
769
770 // Extract minimum node with rebalancing
771 // Returns the extracted min and updates p to the new root
772 static Node * extract_min_rb(Node *& p) noexcept
773 {
774 if (p == Node::NullPtr)
775 return Node::NullPtr;
776
777 if (LLINK(p) == Node::NullPtr)
778 {
779 Node * ret = p;
780 p = RLINK(p);
781 ret->reset();
782 return ret;
783 }
784
785 // Use recursive approach with fix-up
786 struct ExtractHelper
787 {
788 static Node * extract(Node *& p, bool & height_decreased) noexcept
789 {
790 if (LLINK(p) == Node::NullPtr)
791 {
792 Node * ret = p;
793 height_decreased = (COLOR(p) == BLACK);
794 p = RLINK(p);
795 ret->reset();
796 return ret;
797 }
798
799 bool child_decreased = false;
801 --COUNT(p);
802
803 if (child_decreased)
804 {
805 // Left subtree's black height decreased
806 // Need to rebalance
807 Node * s = RLINK(p); // sibling
808 if (s != Node::NullPtr)
809 {
810 if (COLOR(s) == RED)
811 {
812 // Case 1: sibling is red
813 p = rotate_left_simple(p);
814 COLOR(p) = BLACK;
815 COLOR(LLINK(p)) = RED;
816 // Continue fixing in LLINK(p)
817 s = RLINK(LLINK(p));
818 }
819
820 if (s != Node::NullPtr)
821 {
822 if ((LLINK(s) == Node::NullPtr or COLOR(LLINK(s)) == BLACK) and
823 (RLINK(s) == Node::NullPtr or COLOR(RLINK(s)) == BLACK))
824 {
825 // Case 2: sibling and its children are black
826 COLOR(s) = RED;
827 if (COLOR(p) == RED)
828 {
829 COLOR(p) = BLACK;
830 height_decreased = false;
831 }
832 else
833 height_decreased = true;
834 }
835 else
836 {
837 // Case 3 or 4: sibling has a red child
838 if (RLINK(s) == Node::NullPtr or COLOR(RLINK(s)) == BLACK)
839 {
840 // Case 3: left child of sibling is red
841 COLOR(LLINK(s)) = BLACK;
842 COLOR(s) = RED;
843 RLINK(p) = rotate_right_simple(s);
844 }
845 // Case 4: right child of sibling is red
846 Color old_color = COLOR(p);
847 p = rotate_left_simple(p);
848 COLOR(p) = old_color;
849 COLOR(LLINK(p)) = BLACK;
850 if (RLINK(p) != Node::NullPtr)
851 COLOR(RLINK(p)) = BLACK;
852 height_decreased = false;
853 }
854 }
855 else
856 height_decreased = (COLOR(p) == BLACK);
857 }
858 else
859 height_decreased = (COLOR(p) == BLACK);
860 }
861 else
862 height_decreased = false;
863
864 return ret;
865 }
866 };
867
868 bool dummy = false;
869 return ExtractHelper::extract(p, dummy);
870 }
871
872 // Extract maximum node with rebalancing
873 static Node * extract_max_rb(Node *& p) noexcept
874 {
875 if (p == Node::NullPtr)
876 return Node::NullPtr;
877
878 if (RLINK(p) == Node::NullPtr)
879 {
880 Node * ret = p;
881 p = LLINK(p);
882 ret->reset();
883 return ret;
884 }
885
886 struct ExtractHelper
887 {
888 static Node * extract(Node *& p, bool & height_decreased) noexcept
889 {
890 if (RLINK(p) == Node::NullPtr)
891 {
892 Node * ret = p;
893 height_decreased = (COLOR(p) == BLACK);
894 p = LLINK(p);
895 ret->reset();
896 return ret;
897 }
898
899 bool child_decreased = false;
901 --COUNT(p);
902
903 if (child_decreased)
904 {
905 Node * s = LLINK(p); // sibling
906 if (s != Node::NullPtr)
907 {
908 if (COLOR(s) == RED)
909 {
910 p = rotate_right_simple(p);
911 COLOR(p) = BLACK;
912 COLOR(RLINK(p)) = RED;
913 s = LLINK(RLINK(p));
914 }
915
916 if (s != Node::NullPtr)
917 {
918 if ((LLINK(s) == Node::NullPtr or COLOR(LLINK(s)) == BLACK) and
919 (RLINK(s) == Node::NullPtr or COLOR(RLINK(s)) == BLACK))
920 {
921 COLOR(s) = RED;
922 if (COLOR(p) == RED)
923 {
924 COLOR(p) = BLACK;
925 height_decreased = false;
926 }
927 else
928 height_decreased = true;
929 }
930 else
931 {
932 if (LLINK(s) == Node::NullPtr or COLOR(LLINK(s)) == BLACK)
933 {
934 COLOR(RLINK(s)) = BLACK;
935 COLOR(s) = RED;
936 LLINK(p) = rotate_left_simple(s);
937 }
938 Color old_color = COLOR(p);
939 p = rotate_right_simple(p);
940 COLOR(p) = old_color;
941 COLOR(RLINK(p)) = BLACK;
942 if (LLINK(p) != Node::NullPtr)
943 COLOR(LLINK(p)) = BLACK;
944 height_decreased = false;
945 }
946 }
947 else
948 height_decreased = (COLOR(p) == BLACK);
949 }
950 else
951 height_decreased = (COLOR(p) == BLACK);
952 }
953 else
954 height_decreased = false;
955
956 return ret;
957 }
958 };
959
960 bool dummy = false;
961 return ExtractHelper::extract(p, dummy);
962 }
963
964 // Join two RB trees with a pivot node
965 // All keys in t1 < pivot < all keys in t2
966 // bh1 and bh2 are black heights
967 static Node * join_with_pivot_rb(Node * t1, size_t bh1, Node * pivot,
968 Node * t2, size_t bh2) noexcept
969 {
970 if (bh1 == bh2)
971 {
972 // Simple case: equal black heights
973 LLINK(pivot) = t1;
974 RLINK(pivot) = t2;
975 COLOR(pivot) = RED;
976 COUNT(pivot) = COUNT(t1) + COUNT(t2) + 1;
977 return pivot;
978 }
979
980 if (bh1 > bh2)
981 {
982 // t1 is taller (more black nodes), descend right spine
983 return join_right_rb(t1, bh1, pivot, t2, bh2);
984 }
985 // t2 is taller, descend left spine
986 return join_left_rb(t1, bh1, pivot, t2, bh2);
987 }
988
989 // Join when bh1 > bh2
990 static Node * join_right_rb(Node * t1, size_t bh1, Node * pivot,
991 Node * t2, size_t bh2) noexcept
992 {
993 if (t1 == Node::NullPtr)
994 {
995 LLINK(pivot) = Node::NullPtr;
996 RLINK(pivot) = t2;
997 COLOR(pivot) = BLACK;
998 COUNT(pivot) = COUNT(t2) + 1;
999 return pivot;
1000 }
1001
1002 // Descend right spine until black height matches bh2
1003 size_t curr_bh = bh1;
1004 if (COLOR(t1) == BLACK)
1005 --curr_bh;
1006
1007 if (curr_bh == bh2)
1008 {
1009 // Found the join point
1010 LLINK(pivot) = RLINK(t1);
1011 RLINK(pivot) = t2;
1012 COLOR(pivot) = RED;
1013 COUNT(pivot) = COUNT(RLINK(t1)) + COUNT(t2) + 1;
1014 RLINK(t1) = pivot;
1015 COUNT(t1) = COUNT(LLINK(t1)) + COUNT(pivot) + 1;
1016
1017 // Fix red-red if needed
1018 if (COLOR(t1) == RED)
1019 {
1020 // t1 is red and pivot is red - need rotation
1021 // Since we came from the right, do left rotation
1022 Node * result = rotate_left_simple(t1);
1023 COLOR(result) = BLACK;
1024 COLOR(LLINK(result)) = RED;
1025 return result;
1026 }
1027 return t1;
1028 }
1029
1030 // Continue descending
1033 COUNT(t1) = COUNT(LLINK(t1)) + COUNT(RLINK(t1)) + 1;
1034
1035 // Check for red-red violation
1036 if (COLOR(t1) == BLACK and RLINK(t1) != Node::NullPtr and COLOR(RLINK(t1)) == RED)
1037 {
1038 if (RLINK(RLINK(t1)) != Node::NullPtr and COLOR(RLINK(RLINK(t1))) == RED)
1039 {
1040 Node * result = rotate_left_simple(t1);
1041 COLOR(result) = BLACK;
1042 COLOR(LLINK(result)) = RED;
1043 COLOR(RLINK(result)) = BLACK;
1044 return result;
1045 }
1046 if (LLINK(RLINK(t1)) != Node::NullPtr and COLOR(LLINK(RLINK(t1))) == RED)
1047 {
1049 Node * result = rotate_left_simple(t1);
1050 COLOR(result) = BLACK;
1051 COLOR(LLINK(result)) = RED;
1052 COLOR(RLINK(result)) = BLACK;
1053 return result;
1054 }
1055 }
1056
1057 return t1;
1058 }
1059
1060 // Join when bh2 > bh1
1061 static Node * join_left_rb(Node * t1, size_t bh1, Node * pivot,
1062 Node * t2, size_t bh2) noexcept
1063 {
1064 if (t2 == Node::NullPtr)
1065 {
1066 LLINK(pivot) = t1;
1067 RLINK(pivot) = Node::NullPtr;
1068 COLOR(pivot) = BLACK;
1069 COUNT(pivot) = COUNT(t1) + 1;
1070 return pivot;
1071 }
1072
1073 size_t curr_bh = bh2;
1074 if (COLOR(t2) == BLACK)
1075 --curr_bh;
1076
1077 if (curr_bh == bh1)
1078 {
1079 RLINK(pivot) = LLINK(t2);
1080 LLINK(pivot) = t1;
1081 COLOR(pivot) = RED;
1082 COUNT(pivot) = COUNT(t1) + COUNT(LLINK(t2)) + 1;
1083 LLINK(t2) = pivot;
1084 COUNT(t2) = COUNT(pivot) + COUNT(RLINK(t2)) + 1;
1085
1086 if (COLOR(t2) == RED)
1087 {
1088 Node * result = rotate_right_simple(t2);
1089 COLOR(result) = BLACK;
1090 COLOR(RLINK(result)) = RED;
1091 return result;
1092 }
1093 return t2;
1094 }
1095
1097 LLINK(t2) = left_result;
1098 COUNT(t2) = COUNT(LLINK(t2)) + COUNT(RLINK(t2)) + 1;
1099
1100 // Check for red-red violation
1101 if (COLOR(t2) == BLACK and LLINK(t2) != Node::NullPtr and COLOR(LLINK(t2)) == RED)
1102 {
1103 if (LLINK(LLINK(t2)) != Node::NullPtr and COLOR(LLINK(LLINK(t2))) == RED)
1104 {
1105 Node * result = rotate_right_simple(t2);
1106 COLOR(result) = BLACK;
1107 COLOR(LLINK(result)) = BLACK;
1108 COLOR(RLINK(result)) = RED;
1109 return result;
1110 }
1111 if (RLINK(LLINK(t2)) != Node::NullPtr and COLOR(RLINK(LLINK(t2))) == RED)
1112 {
1114 Node * result = rotate_right_simple(t2);
1115 COLOR(result) = BLACK;
1116 COLOR(LLINK(result)) = BLACK;
1117 COLOR(RLINK(result)) = RED;
1118 return result;
1119 }
1120 }
1121
1122 return t2;
1123 }
1124
1125 // Recursive join of two RB trees
1127 Node * t2, size_t bh2) noexcept
1128 {
1129 if (t1 == Node::NullPtr)
1130 return t2;
1131 if (t2 == Node::NullPtr)
1132 return t1;
1133
1134 // Extract a pivot from the larger tree
1135 Node * pivot;
1136 if (bh1 >= bh2)
1137 {
1139 if (t1 != Node::NullPtr)
1140 bh1 = black_height(t1);
1141 else
1142 bh1 = 0;
1143 }
1144 else
1145 {
1147 if (t2 != Node::NullPtr)
1148 bh2 = black_height(t2);
1149 else
1150 bh2 = 0;
1151 }
1152
1153 return join_with_pivot_rb(t1, bh1, pivot, t2, bh2);
1154 }
1155
1156 // Split by key recursively
1157 Node * split_key_rec_rb(Node * p, const Key & key,
1158 Node *& t1, Node *& t2) noexcept
1159 {
1160 if (p == Node::NullPtr)
1161 {
1162 t1 = t2 = Node::NullPtr;
1163 return Node::NullPtr;
1164 }
1165
1166 Node * found;
1167 if (cmp(key, KEY(p)))
1168 {
1169 Node * left_t2;
1170 found = split_key_rec_rb(LLINK(p), key, t1, left_t2);
1171
1172 LLINK(p) = Node::NullPtr;
1173 const size_t left_t2_bh = (left_t2 != Node::NullPtr) ? black_height(left_t2) : 0;
1174 const size_t right_bh = (RLINK(p) != Node::NullPtr) ? black_height(RLINK(p)) : 0;
1175
1176 Node * right_tree = RLINK(p);
1177 RLINK(p) = Node::NullPtr;
1178 COUNT(p) = 1;
1179 COLOR(p) = RED;
1180
1182 if (t2 != Node::NullPtr)
1183 COLOR(t2) = BLACK;
1184 }
1185 else if (cmp(KEY(p), key))
1186 {
1187 Node * right_t1;
1188 found = split_key_rec_rb(RLINK(p), key, right_t1, t2);
1189
1190 RLINK(p) = Node::NullPtr;
1191 const size_t right_t1_bh = (right_t1 != Node::NullPtr) ? black_height(right_t1) : 0;
1192 const size_t left_bh = (LLINK(p) != Node::NullPtr) ? black_height(LLINK(p)) : 0;
1193
1194 Node * left_tree = LLINK(p);
1195 LLINK(p) = Node::NullPtr;
1196 COUNT(p) = 1;
1197 COLOR(p) = RED;
1198
1200 if (t1 != Node::NullPtr)
1201 COLOR(t1) = BLACK;
1202 }
1203 else
1204 {
1205 t1 = LLINK(p);
1206 t2 = RLINK(p);
1207 LLINK(p) = RLINK(p) = Node::NullPtr;
1208 COUNT(p) = 1;
1209 COLOR(p) = RED;
1210 found = p;
1211 if (t1 != Node::NullPtr)
1212 COLOR(t1) = BLACK;
1213 if (t2 != Node::NullPtr)
1214 COLOR(t2) = BLACK;
1215 }
1216
1217 return found;
1218 }
1219
1220 // Split by key including duplicates
1221 void split_key_dup_rec_rb(Node * p, const Key & key,
1222 Node *& t1, Node *& t2) noexcept
1223 {
1224 if (p == Node::NullPtr)
1225 {
1226 t1 = t2 = Node::NullPtr;
1227 return;
1228 }
1229
1230 if (cmp(key, KEY(p)))
1231 {
1232 Node * left_t2;
1234
1235 LLINK(p) = Node::NullPtr;
1236 const size_t left_t2_bh = (left_t2 != Node::NullPtr) ? black_height(left_t2) : 0;
1237 const size_t right_bh = (RLINK(p) != Node::NullPtr) ? black_height(RLINK(p)) : 0;
1238
1239 Node * right_tree = RLINK(p);
1240 RLINK(p) = Node::NullPtr;
1241 COUNT(p) = 1;
1242 COLOR(p) = RED;
1243
1245 if (t2 != Node::NullPtr)
1246 COLOR(t2) = BLACK;
1247 }
1248 else
1249 {
1250 Node * right_t1;
1252
1253 RLINK(p) = Node::NullPtr;
1254 const size_t right_t1_bh = (right_t1 != Node::NullPtr) ? black_height(right_t1) : 0;
1255 const size_t left_bh = (LLINK(p) != Node::NullPtr) ? black_height(LLINK(p)) : 0;
1256
1257 Node * left_tree = LLINK(p);
1258 LLINK(p) = Node::NullPtr;
1259 COUNT(p) = 1;
1260 COLOR(p) = RED;
1261
1263 if (t1 != Node::NullPtr)
1264 COLOR(t1) = BLACK;
1265 }
1266 }
1267
1268 // Split by position recursively
1269 void split_pos_rec_rb(Node * p, size_t pos, Node *& t1, Node *& t2) noexcept
1270 {
1271 if (p == Node::NullPtr)
1272 {
1273 t1 = t2 = Node::NullPtr;
1274 return;
1275 }
1276
1277 size_t left_count = COUNT(LLINK(p));
1278
1279 if (pos <= left_count)
1280 {
1281 Node * left_t2;
1282 split_pos_rec_rb(LLINK(p), pos, t1, left_t2);
1283
1284 LLINK(p) = Node::NullPtr;
1285 const size_t left_t2_bh = (left_t2 != Node::NullPtr) ? black_height(left_t2) : 0;
1286 const size_t right_bh = (RLINK(p) != Node::NullPtr) ? black_height(RLINK(p)) : 0;
1287
1288 Node * right_tree = RLINK(p);
1289 RLINK(p) = Node::NullPtr;
1290 COUNT(p) = 1;
1291 COLOR(p) = RED;
1292
1294 if (t2 != Node::NullPtr)
1295 COLOR(t2) = BLACK;
1296 }
1297 else
1298 {
1299 Node * right_t1;
1300 split_pos_rec_rb(RLINK(p), pos - left_count - 1, right_t1, t2);
1301
1302 RLINK(p) = Node::NullPtr;
1303 const size_t right_t1_bh = (right_t1 != Node::NullPtr) ? black_height(right_t1) : 0;
1304 const size_t left_bh = (LLINK(p) != Node::NullPtr) ? black_height(LLINK(p)) : 0;
1305
1306 Node * left_tree = LLINK(p);
1307 LLINK(p) = Node::NullPtr;
1308 COUNT(p) = 1;
1309 COLOR(p) = RED;
1310
1312 if (t1 != Node::NullPtr)
1313 COLOR(t1) = BLACK;
1314 }
1315 }
1316
1317public:
1318
1328 {
1329 if (t.root == Node::NullPtr)
1330 return;
1331
1332 if (root == Node::NullPtr)
1333 {
1334 root = t.root;
1335 t.root = Node::NullPtr;
1336 return;
1337 }
1338
1339 // Collect nodes from t in preorder and insert them one by one
1340 // This is O(m log(n+m)) but guarantees correctness
1341 FixedStack<Node*> stack(Node::MaxHeight);
1342 stack.push(t.root);
1343 t.root = Node::NullPtr;
1344
1345 while (not stack.is_empty())
1346 {
1347 Node * p = stack.pop();
1348 Node * left = LLINK(p);
1349 Node * right = RLINK(p);
1350
1351 // Reset node and insert
1352 p->reset();
1353 insert(p);
1354
1355 if (right != Node::NullPtr)
1356 stack.push(right);
1357 if (left != Node::NullPtr)
1358 stack.push(left);
1359 }
1360 }
1361
1375 Node * split_key(const Key & key, Gen_Rb_Tree_Rk & t1,
1376 Gen_Rb_Tree_Rk & t2) noexcept
1377 {
1378 if (root == Node::NullPtr)
1379 return nullptr;
1380
1381 // Simple O(n) implementation: iterate through tree and partition
1382 Node * found = nullptr;
1383 FixedStack<Node*> stack(Node::MaxHeight);
1384 stack.push(root);
1385 root = Node::NullPtr;
1386
1387 while (not stack.is_empty())
1388 {
1389 Node * p = stack.pop();
1390 Node * left = LLINK(p);
1391 Node * right = RLINK(p);
1392
1393 if (right != Node::NullPtr)
1394 stack.push(right);
1395 if (left != Node::NullPtr)
1396 stack.push(left);
1397
1398 p->reset();
1399
1400 if (cmp(KEY(p), key))
1401 t1.insert(p);
1402 else if (cmp(key, KEY(p)))
1403 t2.insert(p);
1404 else
1405 found = p; // Found the key
1406 }
1407
1408 return found;
1409 }
1410
1423 void split_key_dup(const Key & key, Gen_Rb_Tree_Rk & t1,
1424 Gen_Rb_Tree_Rk & t2) noexcept
1425 {
1426 if (root == Node::NullPtr)
1427 return;
1428
1429 FixedStack<Node*> stack(Node::MaxHeight);
1430 stack.push(root);
1431 root = Node::NullPtr;
1432
1433 while (not stack.is_empty())
1434 {
1435 Node * p = stack.pop();
1436 Node * left = LLINK(p);
1437 Node * right = RLINK(p);
1438
1439 if (right != Node::NullPtr)
1440 stack.push(right);
1441 if (left != Node::NullPtr)
1442 stack.push(left);
1443
1444 p->reset();
1445
1446 if (cmp(key, KEY(p)))
1447 t2.insert(p);
1448 else
1449 t1.insert_dup(p);
1450 }
1451 }
1452
1465 void split_pos(size_t pos, Gen_Rb_Tree_Rk & t1,
1466 Gen_Rb_Tree_Rk & t2) noexcept
1467 {
1468 if (root == Node::NullPtr)
1469 return;
1470
1471 if (pos == 0)
1472 {
1473 t2.root = root;
1474 root = Node::NullPtr;
1475 return;
1476 }
1477
1478 if (pos >= size())
1479 {
1480 t1.root = root;
1481 root = Node::NullPtr;
1482 return;
1483 }
1484
1485 // Simple O(n) implementation using inorder traversal
1486 size_t count = 0;
1487 FixedStack<Node*> stack(Node::MaxHeight);
1488 Node * curr = root;
1489 root = Node::NullPtr;
1490
1491 // Inorder traversal
1492 while (curr != Node::NullPtr or not stack.is_empty())
1493 {
1494 while (curr != Node::NullPtr)
1495 {
1496 stack.push(curr);
1497 Node * left = LLINK(curr);
1498 LLINK(curr) = Node::NullPtr; // Disconnect
1499 curr = left;
1500 }
1501
1502 curr = stack.pop();
1503 Node * right = RLINK(curr);
1504 curr->reset();
1505
1506 if (count < pos)
1507 t1.insert(curr);
1508 else
1509 t2.insert(curr);
1510
1511 ++count;
1512 curr = right;
1513 }
1514 }
1515
1522 class Iterator : public BinTreeXt_Iterator<Gen_Rb_Tree_Rk, Node, Key, Compare>
1523 {
1525
1526 public:
1527
1528 using Base::Base;
1529 using Base::operator=;
1530 }; // end class Iterator
1531};
1532
1533
1542template <typename Key, class Compare = Aleph::less<Key>>
1543struct Rb_Tree_Rk : public Gen_Rb_Tree_Rk<RbNodeRk, Key, Compare>
1544{
1546 using Base::Base;
1547};
1548
1549
1558template <typename Key, class Compare = Aleph::less<Key>>
1559struct Rb_Tree_Rk_Vtl : public Gen_Rb_Tree_Rk<RbNodeRkVtl, Key, Compare>
1560{
1562 using Base::Base;
1563};
1564
1565
1566} // end namespace Aleph
1567
1568# endif // TPL_RBRK_H
Exception handling system with formatted messages for Aleph-w.
Standard functor implementations and comparison objects.
@ 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.
void empty() noexcept
Empty the stack.
Iterator on nodes of the tree.
Definition tpl_rbRk.H:1523
Red-black tree with rank support (select/position operations).
Definition tpl_rbRk.H:108
static Node * join_exclusive_rec_rb(Node *t1, size_t bh1, Node *t2, size_t bh2) noexcept
Definition tpl_rbRk.H:1126
Node * split_key(const Key &key, Gen_Rb_Tree_Rk &t1, Gen_Rb_Tree_Rk &t2) noexcept
Split tree by key.
Definition tpl_rbRk.H:1375
void update_counters_after_insertion() noexcept
Definition tpl_rbRk.H:439
static Node * join_left_rb(Node *t1, size_t bh1, Node *pivot, Node *t2, size_t bh2) noexcept
Definition tpl_rbRk.H:1061
FixedStack< Node * > rb_stack
Definition tpl_rbRk.H:118
Node * search_and_stack_rb(const Key &key, signed char &cmp_result) noexcept
Search for key and stack ancestors (optimistic duplicate detection)
Definition tpl_rbRk.H:125
size_t size() const noexcept
Definition tpl_rbRk.H:506
Gen_Rb_Tree_Rk(Compare cmp_arg=Compare())
Definition tpl_rbRk.H:464
void join_exclusive(Gen_Rb_Tree_Rk &t) noexcept
Join this tree exclusively with another tree.
Definition tpl_rbRk.H:1327
Node * select(const size_t i) const
Return the i-th node in order sense.
Definition tpl_rbRk.H:640
static Node * join_right_rb(Node *t1, size_t bh1, Node *pivot, Node *t2, size_t bh2) noexcept
Definition tpl_rbRk.H:990
void fix_red_condition(Node *p)
Definition tpl_rbRk.H:236
static Node * extract_min_rb(Node *&p) noexcept
Definition tpl_rbRk.H:772
static Node * rotate_right_simple(Node *p) noexcept
Definition tpl_rbRk.H:692
static constexpr signed char CmpEqual
Definition tpl_rbRk.H:121
virtual ~Gen_Rb_Tree_Rk()=default
static void fix_red_violation(Node *&subtree_root) noexcept
Definition tpl_rbRk.H:714
Node * insert_dup(Node *p)
Definition tpl_rbRk.H:560
void find_succ_and_swap(Node *p, Node *&pp)
Definition tpl_rbRk.H:297
std::pair< long, Node * > find_position(const Key &key) const noexcept
Find the inorder position of a key in the tree.
Definition tpl_rbRk.H:666
void swap(Gen_Rb_Tree_Rk &tree) noexcept
Definition tpl_rbRk.H:469
bool is_empty() const noexcept
Definition tpl_rbRk.H:504
static Node * join_with_pivot_rb(Node *t1, size_t bh1, Node *pivot, Node *t2, size_t bh2) noexcept
Definition tpl_rbRk.H:967
Node * search(const Key &key)
Definition tpl_rbRk.H:496
Node * search_dup_and_stack_rb(const Key &key, signed char &cmp_result)
Definition tpl_rbRk.H:164
bool verify() const
Definition tpl_rbRk.H:581
Node * rotate_to_right_rk(Node *p, Node *pp) noexcept
Definition tpl_rbRk.H:191
void fix_black_condition(Node *p)
Definition tpl_rbRk.H:342
void split_pos(size_t pos, Gen_Rb_Tree_Rk &t1, Gen_Rb_Tree_Rk &t2) noexcept
Split tree by inorder position.
Definition tpl_rbRk.H:1465
static constexpr signed char CmpGreater
Definition tpl_rbRk.H:122
Gen_Rb_Tree_Rk & operator=(Gen_Rb_Tree_Rk &&tree) noexcept
Definition tpl_rbRk.H:483
Node * search_or_insert(Node *p)
Definition tpl_rbRk.H:534
Compare & key_comp() noexcept
Definition tpl_rbRk.H:460
Node * insert(Node *p)
Definition tpl_rbRk.H:508
void update_counters_after_deletion() noexcept
Definition tpl_rbRk.H:449
static Node * rotate_left_simple(Node *p) noexcept
Definition tpl_rbRk.H:702
void split_key_dup(const Key &key, Gen_Rb_Tree_Rk &t1, Gen_Rb_Tree_Rk &t2) noexcept
Split tree by key including duplicates.
Definition tpl_rbRk.H:1423
Node *& getRoot() noexcept
Definition tpl_rbRk.H:502
void split_key_dup_rec_rb(Node *p, const Key &key, Node *&t1, Node *&t2) noexcept
Definition tpl_rbRk.H:1221
static constexpr signed char CmpLess
Definition tpl_rbRk.H:120
Node * remove(const Key &key)
Definition tpl_rbRk.H:583
void split_pos_rec_rb(Node *p, size_t pos, Node *&t1, Node *&t2) noexcept
Definition tpl_rbRk.H:1269
Node * split_key_rec_rb(Node *p, const Key &key, Node *&t1, Node *&t2) noexcept
Definition tpl_rbRk.H:1157
Gen_Rb_Tree_Rk(Gen_Rb_Tree_Rk &&tree) noexcept
Definition tpl_rbRk.H:475
Node * rotate_to_left_rk(Node *p, Node *pp) noexcept
Definition tpl_rbRk.H:214
Compare & get_compare() noexcept
Definition tpl_rbRk.H:462
std::pair< long, Node * > position(const Key &key) const noexcept
Compute the inorder position of a key.
Definition tpl_rbRk.H:651
static Node * extract_max_rb(Node *&p) noexcept
Definition tpl_rbRk.H:873
static size_t black_height(Node *p) noexcept
Definition tpl_rbRk.H:679
NodeType< Key > Node
Definition tpl_rbRk.H:111
void reset() noexcept
Definition htlist.H:516
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_red_black_bst_rk(Node *node, Compare &cmp)
Verify that tree rooted at node is a valid red-black BST with counters.
Definition rbNodeRk.H:170
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
unsigned char Color
Definition rbNodeRk.H:50
#define COLOR(p)
Definition quadnode.H:58
Red-Black tree node with rank (subtree count).
#define BLACK
Black color constant.
Definition rbNode.H:76
#define RED
Red color constant (newly inserted nodes are red)
Definition rbNode.H:73
Red-Black binary search tree with virtual destructor in its nodes and with subtree counters for selec...
Definition tpl_rbRk.H:1560
Red-Black binary search tree with nodes without virtual destructor and with subtree counters for sele...
Definition tpl_rbRk.H:1544
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).
DynList< int > l