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
61namespace Aleph
62{
63
117template <template <typename> class NodeType, typename Key, class Compare>
119{
120public:
122 using key_type = Key;
123 using compare_type = Compare;
124
125private:
130 Compare cmp;
131 size_t num_nodes;
132 static constexpr signed char CmpLess = -1;
133 static constexpr signed char CmpEqual = 0;
134 static constexpr signed char CmpGreater = 1;
135
137 Node * search_and_stack_rb(const Key & key,
138 signed char & cmp_result) noexcept
139 {
140 Node *p = root;
141 Node *candidate = nullptr; // Tracks potential duplicate when going right
142 size_t candidate_pos = 0; // Stack size when candidate was set
143
145 do
146 {
147 rb_stack.push(p);
148 if (cmp(key, KEY(p))) // key < KEY(p)
149 {
151 p = LLINK(p);
152 }
153 else // key >= KEY(p), could be equal
154 {
155 candidate = p;
158 p = RLINK(p);
159 }
160 }
161 while (p != Node::NullPtr);
162
163 // Optimistic duplicate check: when going right, key >= KEY(candidate)
164 // If also KEY(candidate) >= key (i.e., not less), then key == KEY(candidate)
165 if (candidate != nullptr and not cmp(KEY(candidate), key)) [[unlikely]]
166 {
168 // Truncate stack: remove nodes pushed after candidate
170 return candidate;
171 }
172
173 return rb_stack.top();
174 }
175
177 Node * search_dup_and_stack_rb(const Key & key,
178 signed char & cmp_result) noexcept
179 {
180 Node *p = root;
183 do
184 {
185 rb_stack.push(p);
186 const Key & pk = KEY(p);
187 if (cmp(key, pk))
188 {
190 p = LLINK(p);
191 }
192 else
193 {
195 p = RLINK(p);
196 }
197 }
198 while (p != Node::NullPtr);
199
200 return rb_stack.top();
201 }
202
204 void fix_red_condition(Node *p) noexcept
205 {
206 assert(COLOR(p) == RED);
207
208 while (p != root)
209 {
210 Node *pp = rb_stack.pop(); // parent of p
211 if (COLOR(pp) == BLACK) // is p's parent black?
212 break; // yes ==> no consecutive reds ==> done
213
214 if (root == pp) // is p a direct child of the root?
215 {
216 COLOR(root) = BLACK;
217 break;
218 }
219
220 Node *ppp = rb_stack.pop(); // grandparent of p
221 Node *spp = LLINK(ppp) == pp ? RLINK(ppp) : LLINK(ppp); // uncle
222
223 if (COLOR(spp) == RED) // is p's uncle red?
224 {
225 COLOR(ppp) = RED;
226 COLOR(pp) = BLACK;
227 COLOR(spp) = BLACK;
228 p = ppp;
229 continue;
230 }
231
232 Node *pppp = rb_stack.pop(); // great-grandparent of p
233 if (LLINK(pp) == p and LLINK(ppp) == pp)
234 {
236 COLOR(pp) = BLACK;
237 }
238 else if (RLINK(pp) == p and RLINK(ppp) == pp)
239 {
241 COLOR(pp) = BLACK;
242 }
243 else
244 {
245 if (RLINK(pp) == p)
246 {
249 }
250 else
251 {
254 }
255 COLOR(p) = BLACK;
256 }
257
258 COLOR(ppp) = RED;
259 break;
260 }
261
262 rb_stack.empty();
263 }
264
266 void find_succ_and_swap(Node *p, Node *& pp) noexcept
267 {
269
270 Node *fSucc = p;
271 Node *succ = RLINK(p);
272 rb_stack.push(succ);
273
274 while (LLINK(succ) != Node::NullPtr)
275 {
276 fSucc = succ;
277 succ = LLINK(succ);
278 rb_stack.push(succ);
279 }
280
281 ref_rb_stack = succ;
282 rb_stack.top() = p;
283
284 if (LLINK(pp) == p)
285 LLINK(pp) = succ;
286 else
287 RLINK(pp) = succ;
288
289 LLINK(succ) = LLINK(p);
290 LLINK(p) = Node::NullPtr;
291
292 if (RLINK(p) == succ)
293 {
294 RLINK(p) = RLINK(succ);
295 RLINK(succ) = p;
296 pp = succ;
297 }
298 else
299 {
300 Node *succr = RLINK(succ);
301 RLINK(succ) = RLINK(p);
302 LLINK(fSucc) = p;
303 RLINK(p) = succr;
304 pp = fSucc;
305 }
306
307 std::swap(COLOR(succ), COLOR(p));
308 }
309
311 void fix_black_condition(Node *p) noexcept
312 {
313 if (COLOR(p) == RED)
314 {
315 COLOR(p) = BLACK;
316 return;
317 }
318
319 Node *pp = rb_stack.popn(2);
320 while (p != root)
321 {
322 assert(LLINK(pp) == p or RLINK(pp) == p);
324
325 Node *sp = LLINK(pp) == p ? RLINK(pp) : LLINK(pp);
326 if (COLOR(sp) == RED)
327 {
328 Node *& ppp = rb_stack.top();
329
330 if (LLINK(pp) == p)
331 {
332 sp = LLINK(sp);
334 }
335 else
336 {
337 sp = RLINK(sp);
339 }
340
341 COLOR(ppp) = BLACK;
342 COLOR(pp) = RED;
343 }
344
345 Node *np, *snp;
346 if (LLINK(pp) == p)
347 {
348 np = RLINK(sp);
349 snp = LLINK(sp);
350 }
351 else
352 {
353 np = LLINK(sp);
354 snp = RLINK(sp);
355 }
356
357 if (COLOR(np) == RED)
358 {
359 Node *ppp = rb_stack.top();
360
361 if (RLINK(sp) == np)
363 else
365
366 COLOR(sp) = COLOR(pp);
367 COLOR(pp) = BLACK;
368 COLOR(np) = BLACK;
369
370 return;
371 }
372
373 if (COLOR(snp) == RED)
374 {
375 Node *ppp = rb_stack.top();
376
377 if (LLINK(sp) == snp)
378 {
381 }
382 else
383 {
386 }
387
388 COLOR(snp) = COLOR(pp);
389 COLOR(pp) = BLACK;
390
391 return;
392 }
393
394 if (COLOR(pp) == RED)
395 {
396 COLOR(pp) = BLACK;
397 COLOR(sp) = RED;
398 return;
399 }
400
401 COLOR(sp) = RED;
402 p = pp;
403 pp = rb_stack.pop();
404 }
405 }
406
409 {
410 num_nodes = 0;
411 }
412
413public:
415 Compare & key_comp() noexcept { return cmp; }
416 const Compare & key_comp() const noexcept { return cmp; }
417
419 Compare & get_compare() noexcept { return cmp; }
420 const Compare & get_compare() const noexcept { return cmp; }
421
423 Gen_Rb_Tree(Compare __cmp = Compare()) noexcept
424 : head(&head_node), root(head_node.getR()),
425 rb_stack(Node::MaxHeight), cmp(__cmp), num_nodes(0)
426 {
427 /* empty */
428 }
429
433 void swap(Gen_Rb_Tree & tree) noexcept
434 {
435 std::swap(root, tree.root);
436 std::swap(num_nodes, tree.num_nodes);
437 std::swap(cmp, tree.cmp);
438 }
439
442 : head(&head_node), root(head_node.getR()),
443 rb_stack(Node::MaxHeight), cmp(std::move(tree.cmp)),
444 num_nodes(tree.num_nodes)
445 {
446 root = tree.root;
447 tree.root = Node::NullPtr;
448 tree.num_nodes = 0;
449 }
450
453 {
454 if (this != &tree)
455 {
456 root = tree.root;
457 num_nodes = tree.num_nodes;
458 cmp = std::move(tree.cmp);
459 tree.root = Node::NullPtr;
460 tree.num_nodes = 0;
461 }
462 return *this;
463 }
464
466 virtual ~Gen_Rb_Tree() = default;
467
472 Node * search(const Key & key) const noexcept
473 {
474 Node *p = root;
475 while (p != Node::NullPtr)
476 {
477 if (cmp(key, KEY(p)))
478 p = LLINK(p);
479 else if (cmp(KEY(p), key))
480 p = RLINK(p);
481 else
482 return p;
483 }
484 return nullptr;
485 }
486
488 Node *& getRoot() noexcept { return root; }
489
492
494 bool is_empty() const noexcept { return root == Node::NullPtr; }
495
497 size_t size() const noexcept { return num_nodes; }
498
501 {
502 root = Node::NullPtr;
503 num_nodes = 0;
504 }
505
511 Node * insert(Node *p) noexcept
512 {
513 assert(p != nullptr and p != Node::NullPtr);
514 assert(COLOR(p) == RED);
515
516 if (root == Node::NullPtr)
517 {
518 ++num_nodes;
519 return root = p;
520 }
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; // duplicate key
532 }
533
534 ++num_nodes;
536
537 return p;
538 }
539
546 {
547 assert(p != nullptr and p != Node::NullPtr);
548 assert(COLOR(p) == RED);
549
550 if (root == Node::NullPtr)
551 {
552 ++num_nodes;
553 return root = p;
554 }
555
556 signed char cmp_result = CmpEqual;
558 if (cmp_result == CmpLess)
559 LLINK(q) = p;
560 else if (cmp_result == CmpGreater)
561 RLINK(q) = p;
562 else
563 {
564 rb_stack.empty();
565 return q; // return existing node
566 }
567
568 ++num_nodes;
570
571 return p;
572 }
573
579 Node * insert_dup(Node *p) noexcept
580 {
581 assert(p != nullptr and p != Node::NullPtr);
582 assert(COLOR(p) == RED);
583
584 if (root == Node::NullPtr)
585 {
586 ++num_nodes;
587 return root = p;
588 }
589
590 signed char cmp_result = CmpEqual;
592 if (cmp_result == CmpLess)
593 LLINK(q) = p;
594 else
595 RLINK(q) = p;
596
597 ++num_nodes;
599
600 return p;
601 }
602
605
611 Node * remove(const Key & key) noexcept
612 {
613 if (root == Node::NullPtr)
614 return nullptr;
615
616 signed char cmp_result = CmpEqual;
618 if (cmp_result != CmpEqual)
619 {
620 rb_stack.empty();
621 return nullptr;
622 }
623
624 Node *pq = rb_stack.top(1);
625 Node *p;
626 while (true)
627 {
628 if (LLINK(q) == Node::NullPtr)
629 {
630 if (LLINK(pq) == q)
631 p = LLINK(pq) = RLINK(q);
632 else
633 p = RLINK(pq) = RLINK(q);
634 break;
635 }
636
637 if (RLINK(q) == Node::NullPtr)
638 {
639 if (LLINK(pq) == q)
640 p = LLINK(pq) = LLINK(q);
641 else
642 p = RLINK(pq) = LLINK(q);
643 break;
644 }
645
647 }
648
649 if (COLOR(q) == BLACK)
651
652 q->reset();
653 rb_stack.empty();
654 --num_nodes;
655
656 return q;
657 }
658
672};
673
681template <typename Key, class Compare = Aleph::less<Key>>
682struct Rb_Tree : public Gen_Rb_Tree<RbNode, Key, Compare>
683{
685 using Base::Base;
686};
687
695template <typename Key, class Compare = Aleph::less<Key>>
696struct Rb_Tree_Vtl : public Gen_Rb_Tree<RbNodeVtl, Key, Compare>
697{
699 using Base::Base;
700};
701
702} // end namespace Aleph
703
704# endif // TPL_RB_TREE_H
Standard functor implementations and comparison objects.
@ KEY
Definition btreepic.C:169
Inorder iterator on the nodes of a binary tree.
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.
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.
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.
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
constexpr Node *& RLINK(Node *p) noexcept
Return the right tree of p.
constexpr Node *& LLINK(Node *p) noexcept
Return a pointer to left subtree.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
#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:208
#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.
Stack implementations backed by dynamic or fixed arrays.
Utility functions for binary tree operations.