Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_rb_tree.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
53# ifndef TPL_RB_TREE_H
54# define TPL_RB_TREE_H
55
56# include <ahFunction.H>
57# include <tpl_arrayStack.H>
58# include <tpl_binNodeUtils.H>
59# include <rbNode.H>
60# include <ah-concepts.H>
61
62namespace Aleph
63{
64
118template <template <typename> class NodeType, typename Key, class Compare>
121{
122public:
124 using key_type = Key;
125 using compare_type = Compare;
126
127private:
132 Compare cmp;
133 size_t num_nodes;
134 static constexpr signed char CmpLess = -1;
135 static constexpr signed char CmpEqual = 0;
136 static constexpr signed char CmpGreater = 1;
137
139 Node * search_and_stack_rb(const Key & key,
140 signed char & cmp_result) noexcept
141 {
142 Node *p = root;
143 Node *candidate = nullptr; // Tracks potential duplicate when going right
144 size_t candidate_pos = 0; // Stack size when candidate was set
145
147 do
148 {
149 rb_stack.push(p);
150 if (cmp(key, KEY(p))) // key < KEY(p)
151 {
153 p = LLINK(p);
154 }
155 else // key >= KEY(p), could be equal
156 {
157 candidate = p;
160 p = RLINK(p);
161 }
162 }
163 while (p != Node::NullPtr);
164
165 // Optimistic duplicate check: when going right, key >= KEY(candidate)
166 // If also KEY(candidate) >= key (i.e., not less), then key == KEY(candidate)
167 if (candidate != nullptr and not cmp(KEY(candidate), key)) [[unlikely]]
168 {
170 // Truncate stack: remove nodes pushed after candidate
171 const size_t to_pop =
174 if (to_pop > 0)
175 rb_stack.popn(static_cast<int>(to_pop));
176 return candidate;
177 }
178
179 return rb_stack.top();
180 }
181
183 Node * search_dup_and_stack_rb(const Key & key,
184 signed char & cmp_result) noexcept
185 {
186 Node *p = root;
189 do
190 {
191 rb_stack.push(p);
192 const Key & pk = KEY(p);
193 if (cmp(key, pk))
194 {
196 p = LLINK(p);
197 }
198 else
199 {
201 p = RLINK(p);
202 }
203 }
204 while (p != Node::NullPtr);
205
206 return rb_stack.top();
207 }
208
210 void fix_red_condition(Node *p) noexcept
211 {
212 assert(COLOR(p) == RED);
213
214 while (p != root)
215 {
216 Node *pp = rb_stack.pop(); // parent of p
217 if (COLOR(pp) == BLACK) // is p's parent black?
218 break; // yes ==> no consecutive reds ==> done
219
220 if (root == pp) // is p a direct child of the root?
221 {
222 COLOR(root) = BLACK;
223 break;
224 }
225
226 Node *ppp = rb_stack.pop(); // grandparent of p
227 Node *spp = LLINK(ppp) == pp ? RLINK(ppp) : LLINK(ppp); // uncle
228
229 if (COLOR(spp) == RED) // is p's uncle red?
230 {
231 COLOR(ppp) = RED;
232 COLOR(pp) = BLACK;
233 COLOR(spp) = BLACK;
234 p = ppp;
235 continue;
236 }
237
238 Node *pppp = rb_stack.pop(); // great-grandparent of p
239 if (LLINK(pp) == p and LLINK(ppp) == pp)
240 {
242 COLOR(pp) = BLACK;
243 }
244 else if (RLINK(pp) == p and RLINK(ppp) == pp)
245 {
247 COLOR(pp) = BLACK;
248 }
249 else
250 {
251 if (RLINK(pp) == p)
252 {
255 }
256 else
257 {
260 }
261 COLOR(p) = BLACK;
262 }
263
264 COLOR(ppp) = RED;
265 break;
266 }
267
268 rb_stack.empty();
269 }
270
272 void find_succ_and_swap(Node *p, Node *& pp) noexcept
273 {
275
276 Node *fSucc = p;
277 Node *succ = RLINK(p);
278 rb_stack.push(succ);
279
280 while (LLINK(succ) != Node::NullPtr)
281 {
282 fSucc = succ;
283 succ = LLINK(succ);
284 rb_stack.push(succ);
285 }
286
287 ref_rb_stack = succ;
288 rb_stack.top() = p;
289
290 if (LLINK(pp) == p)
291 LLINK(pp) = succ;
292 else
293 RLINK(pp) = succ;
294
295 LLINK(succ) = LLINK(p);
296 LLINK(p) = Node::NullPtr;
297
298 if (RLINK(p) == succ)
299 {
300 RLINK(p) = RLINK(succ);
301 RLINK(succ) = p;
302 pp = succ;
303 }
304 else
305 {
306 Node *succr = RLINK(succ);
307 RLINK(succ) = RLINK(p);
308 LLINK(fSucc) = p;
309 RLINK(p) = succr;
310 pp = fSucc;
311 }
312
313 std::swap(COLOR(succ), COLOR(p));
314 }
315
317 void fix_black_condition(Node *p) noexcept
318 {
319 if (COLOR(p) == RED)
320 {
321 COLOR(p) = BLACK;
322 return;
323 }
324
325 Node *pp = rb_stack.popn(2);
326 while (p != root)
327 {
328 assert(LLINK(pp) == p or RLINK(pp) == p);
330
331 Node *sp = LLINK(pp) == p ? RLINK(pp) : LLINK(pp);
332 if (COLOR(sp) == RED)
333 {
334 Node *& ppp = rb_stack.top();
335
336 if (LLINK(pp) == p)
337 {
338 sp = LLINK(sp);
340 }
341 else
342 {
343 sp = RLINK(sp);
345 }
346
347 COLOR(ppp) = BLACK;
348 COLOR(pp) = RED;
349 }
350
351 Node *np, *snp;
352 if (LLINK(pp) == p)
353 {
354 np = RLINK(sp);
355 snp = LLINK(sp);
356 }
357 else
358 {
359 np = LLINK(sp);
360 snp = RLINK(sp);
361 }
362
363 if (COLOR(np) == RED)
364 {
365 Node *ppp = rb_stack.top();
366
367 if (RLINK(sp) == np)
369 else
371
372 COLOR(sp) = COLOR(pp);
373 COLOR(pp) = BLACK;
374 COLOR(np) = BLACK;
375
376 return;
377 }
378
379 if (COLOR(snp) == RED)
380 {
381 Node *ppp = rb_stack.top();
382
383 if (LLINK(sp) == snp)
384 {
387 }
388 else
389 {
392 }
393
394 COLOR(snp) = COLOR(pp);
395 COLOR(pp) = BLACK;
396
397 return;
398 }
399
400 if (COLOR(pp) == RED)
401 {
402 COLOR(pp) = BLACK;
403 COLOR(sp) = RED;
404 return;
405 }
406
407 COLOR(sp) = RED;
408 p = pp;
409 pp = rb_stack.pop();
410 }
411 }
412
415 {
416 num_nodes = 0;
417 }
418
419public:
421 Compare & key_comp() noexcept { return cmp; }
422 const Compare & key_comp() const noexcept { return cmp; }
423
425 Compare & get_compare() noexcept { return cmp; }
426 const Compare & get_compare() const noexcept { return cmp; }
427
429 Gen_Rb_Tree(Compare __cmp = Compare()) noexcept
430 : head(&head_node), root(head_node.getR()),
431 rb_stack(Node::MaxHeight), cmp(__cmp), num_nodes(0)
432 {
433 /* empty */
434 }
435
439 void swap(Gen_Rb_Tree & tree) noexcept
440 {
441 std::swap(root, tree.root);
442 std::swap(num_nodes, tree.num_nodes);
443 std::swap(cmp, tree.cmp);
444 }
445
448 : head(&head_node), root(head_node.getR()),
449 rb_stack(Node::MaxHeight), cmp(std::move(tree.cmp)),
450 num_nodes(tree.num_nodes)
451 {
452 root = tree.root;
453 tree.root = Node::NullPtr;
454 tree.num_nodes = 0;
455 }
456
459 {
460 if (this != &tree)
461 {
462 root = tree.root;
463 num_nodes = tree.num_nodes;
464 cmp = std::move(tree.cmp);
465 tree.root = Node::NullPtr;
466 tree.num_nodes = 0;
467 }
468 return *this;
469 }
470
472 virtual ~Gen_Rb_Tree() = default;
473
478 Node * search(const Key & key) const noexcept
479 {
480 Node *p = root;
481 while (p != Node::NullPtr)
482 {
483 if (cmp(key, KEY(p)))
484 p = LLINK(p);
485 else if (cmp(KEY(p), key))
486 p = RLINK(p);
487 else
488 return p;
489 }
490 return nullptr;
491 }
492
494 Node *& getRoot() noexcept { return root; }
495
498
500 bool is_empty() const noexcept { return root == Node::NullPtr; }
501
503 size_t size() const noexcept { return num_nodes; }
504
507 {
508 root = Node::NullPtr;
509 num_nodes = 0;
510 }
511
517 Node * insert(Node *p) noexcept
518 {
519 assert(p != nullptr and p != Node::NullPtr);
520 assert(COLOR(p) == RED);
521
522 if (root == Node::NullPtr)
523 {
524 ++num_nodes;
525 return root = p;
526 }
527
528 signed char cmp_result = CmpEqual;
530 if (cmp_result == CmpLess)
531 LLINK(q) = p;
532 else if (cmp_result == CmpGreater)
533 RLINK(q) = p;
534 else
535 {
536 rb_stack.empty();
537 return nullptr; // duplicate key
538 }
539
540 ++num_nodes;
542
543 return p;
544 }
545
552 {
553 assert(p != nullptr and p != Node::NullPtr);
554 assert(COLOR(p) == RED);
555
556 if (root == Node::NullPtr)
557 {
558 ++num_nodes;
559 return root = p;
560 }
561
562 signed char cmp_result = CmpEqual;
564 if (cmp_result == CmpLess)
565 LLINK(q) = p;
566 else if (cmp_result == CmpGreater)
567 RLINK(q) = p;
568 else
569 {
570 rb_stack.empty();
571 return q; // return existing node
572 }
573
574 ++num_nodes;
576
577 return p;
578 }
579
585 Node * insert_dup(Node *p) noexcept
586 {
587 assert(p != nullptr and p != Node::NullPtr);
588 assert(COLOR(p) == RED);
589
590 if (root == Node::NullPtr)
591 {
592 ++num_nodes;
593 return root = p;
594 }
595
596 signed char cmp_result = CmpEqual;
598 if (cmp_result == CmpLess)
599 LLINK(q) = p;
600 else
601 RLINK(q) = p;
602
603 ++num_nodes;
605
606 return p;
607 }
608
611
617 Node * remove(const Key & key) noexcept
618 {
619 if (root == Node::NullPtr)
620 return nullptr;
621
622 signed char cmp_result = CmpEqual;
624 if (cmp_result != CmpEqual)
625 {
626 rb_stack.empty();
627 return nullptr;
628 }
629
630 Node *pq = rb_stack.top(1);
631 Node *p;
632 while (true)
633 {
634 if (LLINK(q) == Node::NullPtr)
635 {
636 if (LLINK(pq) == q)
637 p = LLINK(pq) = RLINK(q);
638 else
639 p = RLINK(pq) = RLINK(q);
640 break;
641 }
642
643 if (RLINK(q) == Node::NullPtr)
644 {
645 if (LLINK(pq) == q)
646 p = LLINK(pq) = LLINK(q);
647 else
648 p = RLINK(pq) = LLINK(q);
649 break;
650 }
651
653 }
654
655 if (COLOR(q) == BLACK)
657
658 q->reset();
659 rb_stack.empty();
660 --num_nodes;
661
662 return q;
663 }
664
678};
679
687template <typename Key, class Compare = Aleph::less<Key>>
689struct Rb_Tree : public Gen_Rb_Tree<RbNode, Key, Compare>
690{
692 using Base::Base;
693};
694
702template <typename Key, class Compare = Aleph::less<Key>>
704struct Rb_Tree_Vtl : public Gen_Rb_Tree<RbNodeVtl, Key, Compare>
705{
707 using Base::Base;
708};
709
710} // end namespace Aleph
711
712# endif // TPL_RB_TREE_H
C++20 concepts for constraining comparison functors.
Standard functor implementations and comparison objects.
@ KEY
Definition btreepic.C:169
Inorder iterator on the nodes of a binary tree.
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.
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
Red-black binary search tree implementation (bottom-up).
const Compare & get_compare() const noexcept
void reset() noexcept
Reset tree to empty state (does not free nodes)
Node * search_or_insert(Node *p) noexcept
Search for key or insert if not found.
FixedStack< Node * > rb_stack
Stack for ancestor path.
Gen_Rb_Tree & operator=(Gen_Rb_Tree &&tree) noexcept
Move assignment operator.
const Compare & key_comp() const noexcept
size_t num_nodes
Number of nodes in tree.
Node * insert_dup(Node *p) noexcept
Insert a node allowing duplicates.
Gen_Rb_Tree(Compare __cmp=Compare()) noexcept
Default constructor with optional comparator.
Node *& root
Reference to root (right child of head)
Node * insert(Node *p) noexcept
Insert a node into the tree.
Compare cmp
Comparison functor.
Node * search(const Key &key) const noexcept
Search for a key in the tree.
Node * search_and_stack_rb(const Key &key, signed char &cmp_result) noexcept
Search for key and stack ancestors (optimistic duplicate detection)
Node * getRoot() const noexcept
Get const root pointer.
void find_succ_and_swap(Node *p, Node *&pp) noexcept
Find successor and swap with node being deleted.
virtual ~Gen_Rb_Tree()=default
Destructor.
void fix_red_condition(Node *p) noexcept
Fix red-red violation after insertion.
NodeType< Key > Node
size_t size() const noexcept
Returns the number of nodes in the tree (O(1))
Node * head
Pointer to sentinel.
Node head_node
Sentinel header node.
Compare & get_compare() noexcept
bool verify() const noexcept
Verify that tree satisfies red-black properties.
Node *& getRoot() noexcept
Get reference to root pointer.
Node * remove(const Key &key) noexcept
Remove the node containing key.
bool is_empty() const noexcept
Returns true if the tree is empty.
Gen_Rb_Tree(Gen_Rb_Tree &&tree) noexcept
Move constructor.
static constexpr signed char CmpEqual
void init() noexcept
Initialize tree state.
static constexpr signed char CmpLess
void swap(Gen_Rb_Tree &tree) noexcept
Swaps all elements with another tree in constant time.
static constexpr signed char CmpGreater
Node * search_dup_and_stack_rb(const Key &key, signed char &cmp_result) noexcept
Search for insertion point (allows duplicates) and stack ancestors.
void fix_black_condition(Node *p) noexcept
Fix black-height violation after deletion.
Compare & key_comp() noexcept
Returns a reference to the comparison criteria.
Strict weak ordering constraint for BST comparators.
Definition ah-concepts.H:84
Node * rotate_to_left(Node *p) noexcept
Rotate to the left the tree with root p
Node * rotate_to_right(Node *p) noexcept
Rotate to the right the tree with root p
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
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.
#define COLOR(p)
Definition quadnode.H:58
Red-Black tree node definition and validation utilities.
bool is_red_black_bst(Node *node, Compare &cmp)
Verify that tree is both a valid RB tree and valid BST.
Definition rbNode.H:211
#define BLACK
Black color constant.
Definition rbNode.H:76
#define RED
Red color constant (newly inserted nodes are red)
Definition rbNode.H:73
Iterator over tree nodes in sorted order.
Iterator() noexcept=default
Default constructor creates an "end" iterator.
Iterator(const Gen_Rb_Tree &t)
Red-black tree with virtual destructor in nodes.
Red-black tree with nodes without virtual destructor.
#define RLINK(i, n)
#define LLINK(i, n)
Stack implementations backed by dynamic or fixed arrays.
Utility functions for binary tree operations.