Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_rand_tree.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
48# ifndef TPL_RAND_TREE_H
49# define TPL_RAND_TREE_H
50
51# include <ctime>
52# include <climits>
53# include <gsl/gsl_rng.h>
54# include <ahUtils.H>
55# include <ahFunction.H>
56# include <tpl_randNode.H>
57# include <tpl_binTreeOps.H>
58# include <ah-errors.H>
59# include <ah-concepts.H>
60
61using namespace Aleph;
62
63namespace Aleph
64{
151 template <template <typename> class NodeType, typename Key, class Compare>
154 {
155 public:
157
158 private:
161 Compare cmp;
162
163 Node * random_insert(Node *root, Node *p) noexcept
164 {
165 if (root == Node::NullPtr)
166 return p;
167
168 // Prefetch children to reduce memory latency
171
172 const long n = COUNT(root);
173 if (const size_t rn = gsl_rng_uniform_int(r, n + 1); rn == n) [[unlikely]]
175
176 Node *result;
177 const Key & pk = KEY(p);
178 const Key & rk = KEY(root);
179 if (cmp(pk, rk)) // KEY(p) < KEY(root)
180 {
181 result = random_insert(LLINK(root), p);
182 if (result != Node::NullPtr) // p was inserted
183 {
184 LLINK(root) = result;
185 ++COUNT(root);
186 return root;
187 }
188 }
189 else if (cmp(rk, pk)) // KEY(p) > KEY(root)
190 {
191 result = random_insert(RLINK(root), p);
192 if (result != Node::NullPtr) // p was inserted
193 {
194 RLINK(root) = result;
195 ++COUNT(root);
196 return root;
197 }
198 }
199
200 return Node::NullPtr; // duplicated key ==> no insertion
201 }
202
204 {
205 if (root == Node::NullPtr)
206 return p;
207
208 // Prefetch children to reduce memory latency
211
212 const long n = COUNT(root);
213 if (const size_t rn = gsl_rng_uniform_int(r, n + 1); rn == n) [[unlikely]]
215
216 const Key & pk = KEY(p);
217 const Key & rk = KEY(root);
218 if (cmp(pk, rk)) // KEY(p) < KEY(root)
220 else
222
223 ++COUNT(root);
224
225 return root;
226 }
227
229 {
230 if (root == Node::NullPtr)
231 return root = p;
232
233 // Prefetch children to reduce memory latency
234 if (LLINK(root) != Node::NullPtr)
236 if (RLINK(root) != Node::NullPtr)
238
239 const long n = COUNT(root);
240 if (const size_t rn = gsl_rng_uniform_int(r, n + 1); rn == n) [[unlikely]]
241 {
242 if (BinTreeXt_Operation<Node, Compare>(cmp).insert_root(root, p) != Node::NullPtr)
243 return p;
244
246 }
247
248 const Key & pk = KEY(p);
249 const Key & rk = KEY(root);
250 if (cmp(pk, rk))
251 {
253 if (ret == p)
254 ++COUNT(root);
255
256 return ret;
257 }
258 if (cmp(rk, pk))
259 {
261 if (ret == p)
262 ++COUNT(root);
263
264 return ret;
265 }
266
267 return root; // key == root: found existing
268 }
269
270 public:
271 Gen_Rand_Tree(const Gen_Rand_Tree &) = delete;
272
274
275 private:
276 void init(const unsigned long seed)
277 {
279
280 ah_bad_alloc_if(r == nullptr);
281
283 }
284
285 public:
287 Compare &key_comp() noexcept { return cmp; }
288
290 const Compare &key_comp() const noexcept { return cmp; }
291
293 Compare &get_compare() noexcept { return key_comp(); }
294
296 const Compare &get_compare() const noexcept { return cmp; }
297
300
302 void set_seed(const unsigned long seed) noexcept
303 {
305 }
306
309 Gen_Rand_Tree(const unsigned int seed, const Compare & __cmp = Compare())
310 : tree_root(Node::NullPtr), r(nullptr), cmp(__cmp)
311 {
312 init(seed);
313 }
314
317 Gen_Rand_Tree(const Compare & cmp = Compare()) noexcept
318 : Gen_Rand_Tree(time(nullptr), cmp)
319 { /* empty */
320 }
321
323 void swap(Gen_Rand_Tree & tree) noexcept
324 {
325 std::swap(tree_root, tree.tree_root);
326 std::swap(r, tree.r);
327 std::swap(cmp, tree.cmp);
328 }
329
332 : tree_root(other.tree_root), r(other.r), cmp(std::move(other.cmp))
333 {
334 other.tree_root = Node::NullPtr;
335 other.r = nullptr;
336 }
337
340 {
341 if (this != &other)
342 {
343 // Clean up current resources
344 if (r != nullptr)
347
348 // Transfer ownership
349 tree_root = other.tree_root;
350 r = other.r;
351 cmp = std::move(other.cmp);
352
353 // Reset other
354 other.tree_root = Node::NullPtr;
355 other.r = nullptr;
356 }
357 return *this;
358 }
359
361 {
362 if (r != nullptr)
364 // Note: nodes are NOT freed here. DynSetTree::empty() handles node deletion.
365 // The underlying tree only manages the tree structure, not node memory.
366 }
367
374 Node * insert(Node *p) noexcept
375 {
376 assert(p != Node::NullPtr);
377 assert((LLINK(p) == Node::NullPtr) and (RLINK(p) == Node::NullPtr));
378 assert(COUNT(p) == 1);
379
380 Node *result = random_insert(tree_root, p);
381 if (result == Node::NullPtr)
382 return nullptr;
383
384 return tree_root = result;
385 }
386
394 Node * insert_dup(Node *p) noexcept
395 {
396 assert(p != Node::NullPtr);
397 assert((LLINK(p) == Node::NullPtr) and (RLINK(p) == Node::NullPtr));
398 assert(COUNT(p) == 1);
399
401 }
402
403 private:
405 {
406 if (tl == Node::NullPtr)
407 return tr;
408
409 if (tr == Node::NullPtr)
410 return tl;
411
412 const size_t & m = COUNT(tl);
413 const size_t & n = COUNT(tr);
414 if (const size_t rn = 1 + gsl_rng_uniform_int(r, m + n); rn <= m)
415 { // left subtree wins
416 COUNT(tl) += COUNT(tr);
418 return tl;
419 }
420 COUNT(tr) += COUNT(tl);
422 return tr;
423 }
424
425 Node * random_remove(Node *& root, const Key & key) noexcept
426 {
427 if (root == Node::NullPtr)
428 return Node::NullPtr;
429
430 Node *ret_val;
431 const Key & rk = KEY(root);
432 if (cmp(key, rk))
433 {
435 if (ret_val != Node::NullPtr)
436 --COUNT(root);
437
438 return ret_val;
439 }
440 if (cmp(rk, key))
441 {
443 if (ret_val != Node::NullPtr)
444 --COUNT(root);
445
446 return ret_val;
447 }
448
449 // key was found
450 ret_val = root;
452 ret_val->reset();
453
454 return ret_val;
455 }
456
457 public:
464 Node * remove(const Key & key) noexcept
465 {
467
468 return ret_val != Node::NullPtr ? ret_val : nullptr;
469 }
470
477 Node * search(const Key & key) const noexcept
478 {
480 return retVal == Node::NullPtr ? nullptr : retVal;
481 }
482
496 {
497 assert(p != Node::NullPtr);
498 assert(COUNT(p) == 1);
499
501 }
502
504 [[nodiscard]] bool verify() const
505 {
507 }
508
511
519 Node * select(const size_t i) const
520 {
521 return Aleph::select(tree_root, i);
522 }
523
525 [[nodiscard]] size_t size() const noexcept { return COUNT(tree_root); }
526
528 [[nodiscard]] bool is_empty() const noexcept { return tree_root == Node::NullPtr; }
529
539 std::pair<long, Node *> position(const Key & key) const noexcept
540 {
541 std::pair<long, Node *> ret_val;
543 inorder_position(tree_root, key, ret_val.second);
544
545 return ret_val;
546 }
547
574 std::pair<long, Node *> find_position(const Key & key) const noexcept
575 {
576 std::pair<long, Node *> r(-2, nullptr);
577
579 find_position(tree_root, key, r.second);
580
581 return r;
582 }
583
584 private:
585 Node * remove_pos(Node *& root, const size_t pos) noexcept
586 {
587 if (pos == COUNT(LLINK(root)))
588 {
589 Node *ret_val = root;
591 return ret_val;
592 }
593
594 --COUNT(root);
595 if (pos < COUNT(LLINK(root)))
596 return remove_pos(LLINK(root), pos);
597 else
598 return remove_pos(RLINK(root), pos - COUNT(LLINK(root)) - 1);
599 }
600
601 public:
609 Node * remove_pos(const size_t i)
610 {
611 ah_out_of_range_error_if(i >= COUNT(tree_root)) << "infix position out of range";
612
613 return remove_pos(tree_root, i);
614 }
615
624 bool split_key(const Key & key, Gen_Rand_Tree & t1, Gen_Rand_Tree & t2)
625 noexcept
626 {
627 return split_key_rec_xt(tree_root, key, t1.getRoot(), t2.getRoot());
628 }
629
640 void split_key_dup(const Key & key, Gen_Rand_Tree & t1, Gen_Rand_Tree & t2)
641 noexcept
642 {
643 split_key_dup_rec_xt(tree_root, key, t1.getRoot(), t2.getRoot());
644 }
645
657 void split_pos(size_t pos, Gen_Rand_Tree & t1, Gen_Rand_Tree & t2) noexcept
658 {
659 split_pos_rec(tree_root, pos, t1.getRoot(), t2.getRoot());
660 }
661
662 private:
664 {
665 if (t1 == Node::NullPtr)
666 return t2;
667
668 if (t2 == Node::NullPtr)
669 return t1;
670
671 Node *ret = Node::NullPtr;
672 const size_t m = COUNT(t1);
673 const size_t n = COUNT(t2);
674 if (const size_t rn = 1 + gsl_rng_uniform_int(r, m + n); rn <= m)
675 { // root of t1 wins
676 Node *l = LLINK(t1), *r = RLINK(t1);
677 t1->reset();
678 t1_wins:
680 if (ret != Node::NullPtr)
681 {
682 LLINK(ret) = random_join(LLINK(ret), l, dup);
683 RLINK(ret) = random_join(RLINK(ret), r, dup);
684 COUNT(ret) = COUNT(LLINK(ret)) + 1 + COUNT(RLINK(ret));
685 }
686 else
687 {
688 dup = random_insert_dup(dup, random_remove(t2, KEY(t1)));
689 goto t1_wins;
690 }
691 }
692 else
693 { // root of t2 wins
694 Node *l = LLINK(t2), *r = RLINK(t2);
695 t2->reset();
696 t2_wins:
698 if (ret != Node::NullPtr)
699 {
700 LLINK(ret) = random_join(l, LLINK(ret), dup);
701 RLINK(ret) = random_join(r, RLINK(ret), dup);
702 COUNT(ret) = COUNT(LLINK(ret)) + 1 + COUNT(RLINK(ret));
703 }
704 else
705 {
706 dup = random_insert_dup(dup, random_remove(t1, KEY(t2)));
707 goto t2_wins;
708 }
709 }
710
711 return ret;
712 }
713
715 {
716 if (t1 == Node::NullPtr)
717 return t2;
718
719 if (t2 == Node::NullPtr)
720 return t1;
721
722 Node *ret = Node::NullPtr;
723 const size_t & m = COUNT(t1);
724 const size_t & n = COUNT(t2);
725 const size_t total = m + n;
726 if (const size_t rn = 1 + gsl_rng_uniform_int(r, total); rn <= m)
727 { // root of t1 wins
728 Node *l = LLINK(t1), *r = RLINK(t1);
729 t1->reset();
733 }
734 else
735 { // root of t2 wins
736 Node *l = LLINK(t2), *r = RLINK(t2);
737 t2->reset();
741 }
742
743 COUNT(ret) = total;
744 return ret;
745 }
746
747 public:
760 void join(Gen_Rand_Tree & t, Gen_Rand_Tree & dup) noexcept
761 {
762 tree_root = random_join(tree_root, t.tree_root, dup.tree_root);
763 t.tree_root = Node::NullPtr;
764 }
765
774 void join_dup(Gen_Rand_Tree & t) noexcept
775 {
776 tree_root = random_join(tree_root, t.tree_root);
777 t.tree_root = Node::NullPtr;
778 }
779
791 void join_exclusive(Gen_Rand_Tree & t) noexcept
792 {
794 t.tree_root = Node::NullPtr;
795 }
796
803 struct Iterator : public BinNodeInfixIterator<Node>
804 {
806 };
807 };
808
843 template <typename Key, class Compare = Aleph::less<Key>>
845 struct Rand_Tree : public Gen_Rand_Tree<RandNode, Key, Compare>
846 {
848 using Base::Base;
849 };
850
851
881 template <typename Key, class Compare = Aleph::less<Key>>
883 struct Rand_Tree_Vtl : public Gen_Rand_Tree<RandNodeVtl, Key, Compare>
884 {
886 using Base::Base;
887 };
888} // end namespace Aleph
889
890# endif // TPL_RAND_TREE_H
C++20 concepts for constraining comparison functors.
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
#define ah_bad_alloc_if(C)
Throws std::bad_alloc if condition holds.
Definition ah-errors.H:429
Standard functor implementations and comparison objects.
General utility functions and helpers.
@ KEY
Definition btreepic.C:169
Inorder iterator on the nodes of a binary tree.
Functor encompassing basic operation for extended binary search trees.
Node * insert_dup_root(Node *&root, Node *p) noexcept
Insert a node as root of an extended binary search tree.
Randomized binary search tree with rank support.
bool is_empty() const noexcept
Return true if the tree is empty.
Gen_Rand_Tree(const unsigned int seed, const Compare &__cmp=Compare())
Initialize a random tree with random seed and comparison criteria __cmp
bool verify() const
Return true if this is a consistent randomized tree.
const Compare & key_comp() const noexcept
Node * remove(const Key &key) noexcept
Remove a key from the tree.
NodeType< Key > Node
Node * search_or_insert(Node *p) noexcept
Search or insert a key.
Compare & key_comp() noexcept
return the comparison criteria
Node * insert_dup(Node *p) noexcept
Insert a node in the tree.
virtual ~Gen_Rand_Tree() noexcept
Node * random_search_or_insert(Node *&root, Node *p) noexcept
void split_pos(size_t pos, Gen_Rand_Tree &t1, Gen_Rand_Tree &t2) noexcept
Split a extended binary tree according to a position.
std::pair< long, Node * > find_position(const Key &key) const noexcept
Find the inorder position of a key in the tree.
void set_seed(const unsigned long seed) noexcept
Set the random number generator seed.
Compare & get_compare() noexcept
void init(const unsigned long seed)
bool split_key(const Key &key, Gen_Rand_Tree &t1, Gen_Rand_Tree &t2) noexcept
Split the tree according to a key.
Node * insert(Node *p) noexcept
Insert a node in the tree.
void split_key_dup(const Key &key, Gen_Rand_Tree &t1, Gen_Rand_Tree &t2) noexcept
Split the tree according to a key that could be in the tree.
void join_exclusive(Gen_Rand_Tree &t) noexcept
Join exclusive of this with t
size_t size() const noexcept
Return the number of nodes that have the tree.
Node * select(const size_t i) const
Return the i-th node in inorder sense.
Node * remove_pos(const size_t i)
Remove the key at inorder position i
Gen_Rand_Tree(const Gen_Rand_Tree &)=delete
Gen_Rand_Tree(Gen_Rand_Tree &&other) noexcept
Move constructor - transfers ownership of tree and RNG.
const Compare & get_compare() const noexcept
void join_dup(Gen_Rand_Tree &t) noexcept
Join this with t independently of the presence of duplicated keys.
Node * random_insert(Node *root, Node *p) noexcept
gsl_rng * gsl_rng_object() noexcept
Get a pointer to gsl random number generator.
Node * random_remove(Node *&root, const Key &key) noexcept
Node * random_join(Node *t1, Node *t2)
Node *& getRoot() noexcept
Return the tree's root.
void join(Gen_Rand_Tree &t, Gen_Rand_Tree &dup) noexcept
Join this with t filtering the duplicated keys.
Node * random_insert_dup(Node *root, Node *p) noexcept
Node * random_join(Node *t1, Node *t2, Node *&dup)
Gen_Rand_Tree(const Compare &cmp=Compare()) noexcept
Initialize a random tree with random seed from system time and comparison criteria cmp
Node * random_join_exclusive(Node *tl, Node *tr) noexcept
Node * search(const Key &key) const noexcept
Search a key.
void swap(Gen_Rand_Tree &tree) noexcept
Swap in constant time all the nodes of this with tree
Node * remove_pos(Node *&root, const size_t pos) noexcept
Node * tree_root
The type of node.
Gen_Rand_Tree & operator=(const Gen_Rand_Tree &)=delete
Strict weak ordering constraint for BST comparators.
Definition ah-concepts.H:84
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
std::pair< long, Node * > position(const Key &key) const noexcept
Compute the inorder position of a key.
long inorder_position(Node *r, const typename Node::key_type &key, Node *&p, Compare &cmp) noexcept
Compute the inorder position of a key.
Node * insert_dup_root_xt(Node *&root, Node *p, Compare &cmp) noexcept
Insert a node as root of an extended binary search tree.
bool check_rank_tree(Node *root) noexcept
Return true if root is a valid extended binary tree.
void split_pos_rec(Node *&r, const size_t i, Node *&ts, Node *&tg)
Split a extended binary tree according to a position.
Node * insert_root(Node *&root, Node *p) noexcept
Insert a node p as root of an extended binary search tree.
auto & COUNT(Node *p) noexcept
Return the number of nodes of the tree fron p is root.
Node * insert_root_xt(Node *&root, Node *p, Compare &cmp) noexcept
Insert a node p as root of an extended binary search tree.
bool split_key_rec_xt(Node *&root, const typename Node::key_type &key, Node *&l, Node *&r, Compare &cmp) noexcept
Split an extended binary search tree according to a key.
Node * select(Node *r, const size_t pos)
Iterative selection of a node according to inorder position.
void destroyRec(Node *&root) noexcept
Free recursively all the memory occupied by the tree root
Node * insert_root(Node *&root, Node *p, const Compare &cmp=Compare()) noexcept
Insert the node p as root of a binary search tree.
void split_key_dup_rec_xt(Node *&root, const typename Node::key_type &key, Node *&l, Node *&r, Compare &cmp) noexcept
Split an extended binary search tree according to a key which can be in the tree.
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.
static std::atomic< bool > init
Definition hash-fct.C:53
Iterator on nodes of the tree.
Randomized binary search tree.
Randomized binary search tree.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
#define RLINK(i, n)
#define LLINK(i, n)
ValueArg< size_t > seed
Definition testHash.C:48
Binary tree operations (split, join, rotate).
Randomized tree node.
DynList< int > l