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