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
60using namespace Aleph;
61
62namespace Aleph
63{
150 template <template <typename> class NodeType, typename Key, class Compare>
152 {
153 public:
155
156 private:
159 Compare cmp;
160
161 Node * random_insert(Node *root, Node *p) noexcept
162 {
163 if (root == Node::NullPtr)
164 return p;
165
166 // Prefetch children to reduce memory latency
169
170 const long n = COUNT(root);
171 if (const size_t rn = gsl_rng_uniform_int(r, n + 1); rn == n) [[unlikely]]
173
174 Node *result;
175 const Key & pk = KEY(p);
176 const Key & rk = KEY(root);
177 if (cmp(pk, rk)) // KEY(p) < KEY(root)
178 {
179 result = random_insert(LLINK(root), p);
180 if (result != Node::NullPtr) // p was inserted
181 {
182 LLINK(root) = result;
183 ++COUNT(root);
184 return root;
185 }
186 }
187 else if (cmp(rk, pk)) // KEY(p) > KEY(root)
188 {
189 result = random_insert(RLINK(root), p);
190 if (result != Node::NullPtr) // p was inserted
191 {
192 RLINK(root) = result;
193 ++COUNT(root);
194 return root;
195 }
196 }
197
198 return Node::NullPtr; // duplicated key ==> no insertion
199 }
200
202 {
203 if (root == Node::NullPtr)
204 return p;
205
206 // Prefetch children to reduce memory latency
209
210 const long n = COUNT(root);
211 if (const size_t rn = gsl_rng_uniform_int(r, n + 1); rn == n) [[unlikely]]
213
214 const Key & pk = KEY(p);
215 const Key & rk = KEY(root);
216 if (cmp(pk, rk)) // KEY(p) < KEY(root)
218 else
220
221 ++COUNT(root);
222
223 return root;
224 }
225
227 {
228 if (root == Node::NullPtr)
229 return root = p;
230
231 // Prefetch children to reduce memory latency
232 if (LLINK(root) != Node::NullPtr)
234 if (RLINK(root) != Node::NullPtr)
236
237 const long n = COUNT(root);
238 if (const size_t rn = gsl_rng_uniform_int(r, n + 1); rn == n) [[unlikely]]
239 {
240 if (BinTreeXt_Operation<Node, Compare>(cmp).insert_root(root, p) != Node::NullPtr)
241 return p;
242
244 }
245
246 const Key & pk = KEY(p);
247 const Key & rk = KEY(root);
248 if (cmp(pk, rk))
249 {
251 if (ret == p)
252 ++COUNT(root);
253
254 return ret;
255 }
256 if (cmp(rk, pk))
257 {
259 if (ret == p)
260 ++COUNT(root);
261
262 return ret;
263 }
264
265 return root; // key == root: found existing
266 }
267
268 public:
269 Gen_Rand_Tree(const Gen_Rand_Tree &) = delete;
270
272
273 private:
274 void init(const unsigned long seed)
275 {
277
278 ah_bad_alloc_if(r == nullptr);
279
280 gsl_rng_set(r, seed % gsl_rng_max(r));
281 }
282
283 public:
285 Compare &key_comp() noexcept { return cmp; }
286
288 const Compare &key_comp() const noexcept { return cmp; }
289
291 Compare &get_compare() noexcept { return key_comp(); }
292
294 const Compare &get_compare() const noexcept { return cmp; }
295
298
300 void set_seed(const unsigned long seed) noexcept
301 {
302 gsl_rng_set(r, seed % gsl_rng_max(r));
303 }
304
307 Gen_Rand_Tree(const unsigned int seed, const Compare & __cmp = Compare())
308 : tree_root(Node::NullPtr), r(nullptr), cmp(__cmp)
309 {
310 init(seed);
311 }
312
315 Gen_Rand_Tree(const Compare & cmp = Compare()) noexcept
316 : Gen_Rand_Tree(time(nullptr), cmp)
317 { /* empty */
318 }
319
321 void swap(Gen_Rand_Tree & tree) noexcept
322 {
323 std::swap(tree_root, tree.tree_root);
324 std::swap(r, tree.r);
325 std::swap(cmp, tree.cmp);
326 }
327
330 : tree_root(other.tree_root), r(other.r), cmp(std::move(other.cmp))
331 {
332 other.tree_root = Node::NullPtr;
333 other.r = nullptr;
334 }
335
338 {
339 if (this != &other)
340 {
341 // Clean up current resources
342 if (r != nullptr)
345
346 // Transfer ownership
347 tree_root = other.tree_root;
348 r = other.r;
349 cmp = std::move(other.cmp);
350
351 // Reset other
352 other.tree_root = Node::NullPtr;
353 other.r = nullptr;
354 }
355 return *this;
356 }
357
359 {
360 if (r != nullptr)
362 // Note: nodes are NOT freed here. DynSetTree::empty() handles node deletion.
363 // The underlying tree only manages the tree structure, not node memory.
364 }
365
372 Node * insert(Node *p) noexcept
373 {
374 assert(p != Node::NullPtr);
375 assert((LLINK(p) == Node::NullPtr) and (RLINK(p) == Node::NullPtr));
376 assert(COUNT(p) == 1);
377
378 Node *result = random_insert(tree_root, p);
379 if (result == Node::NullPtr)
380 return nullptr;
381
382 return tree_root = result;
383 }
384
392 Node * insert_dup(Node *p) noexcept
393 {
394 assert(p != Node::NullPtr);
395 assert((LLINK(p) == Node::NullPtr) and (RLINK(p) == Node::NullPtr));
396 assert(COUNT(p) == 1);
397
399 }
400
401 private:
403 {
404 if (tl == Node::NullPtr)
405 return tr;
406
407 if (tr == Node::NullPtr)
408 return tl;
409
410 const size_t & m = COUNT(tl);
411 const size_t & n = COUNT(tr);
412 if (const size_t rn = 1 + gsl_rng_uniform_int(r, m + n); rn <= m)
413 { // left subtree wins
414 COUNT(tl) += COUNT(tr);
416 return tl;
417 }
418 COUNT(tr) += COUNT(tl);
420 return tr;
421 }
422
423 Node * random_remove(Node *& root, const Key & key) noexcept
424 {
425 if (root == Node::NullPtr)
426 return Node::NullPtr;
427
428 Node *ret_val;
429 const Key & rk = KEY(root);
430 if (cmp(key, rk))
431 {
433 if (ret_val != Node::NullPtr)
434 --COUNT(root);
435
436 return ret_val;
437 }
438 if (cmp(rk, key))
439 {
441 if (ret_val != Node::NullPtr)
442 --COUNT(root);
443
444 return ret_val;
445 }
446
447 // key was found
448 ret_val = root;
450 ret_val->reset();
451
452 return ret_val;
453 }
454
455 public:
462 Node * remove(const Key & key) noexcept
463 {
465
466 return ret_val != Node::NullPtr ? ret_val : nullptr;
467 }
468
475 Node * search(const Key & key) const noexcept
476 {
478 return retVal == Node::NullPtr ? nullptr : retVal;
479 }
480
494 {
495 assert(p != Node::NullPtr);
496 assert(COUNT(p) == 1);
497
499 }
500
502 [[nodiscard]] bool verify() const
503 {
505 }
506
509
517 Node * select(const size_t i) const
518 {
519 return Aleph::select(tree_root, i);
520 }
521
523 [[nodiscard]] size_t size() const noexcept { return COUNT(tree_root); }
524
526 [[nodiscard]] bool is_empty() const noexcept { return tree_root == Node::NullPtr; }
527
537 std::pair<long, Node *> position(const Key & key) const noexcept
538 {
539 std::pair<long, Node *> ret_val;
541 inorder_position(tree_root, key, ret_val.second);
542
543 return ret_val;
544 }
545
572 std::pair<long, Node *> find_position(const Key & key) const noexcept
573 {
574 std::pair<long, Node *> r(-2, nullptr);
575
577 find_position(tree_root, key, r.second);
578
579 return r;
580 }
581
582 private:
583 Node * remove_pos(Node *& root, const size_t pos) noexcept
584 {
585 if (pos == COUNT(LLINK(root)))
586 {
587 Node *ret_val = root;
589 return ret_val;
590 }
591
592 --COUNT(root);
593 if (pos < COUNT(LLINK(root)))
594 return remove_pos(LLINK(root), pos);
595 else
596 return remove_pos(RLINK(root), pos - COUNT(LLINK(root)) - 1);
597 }
598
599 public:
607 Node * remove_pos(const size_t i)
608 {
609 ah_out_of_range_error_if(i >= COUNT(tree_root)) << "infix position out of range";
610
611 return remove_pos(tree_root, i);
612 }
613
622 bool split_key(const Key & key, Gen_Rand_Tree & t1, Gen_Rand_Tree & t2)
623 noexcept
624 {
625 return split_key_rec_xt(tree_root, key, t1.getRoot(), t2.getRoot());
626 }
627
638 void split_key_dup(const Key & key, Gen_Rand_Tree & t1, Gen_Rand_Tree & t2)
639 noexcept
640 {
641 split_key_dup_rec_xt(tree_root, key, t1.getRoot(), t2.getRoot());
642 }
643
655 void split_pos(size_t pos, Gen_Rand_Tree & t1, Gen_Rand_Tree & t2) noexcept
656 {
657 split_pos_rec(tree_root, pos, t1.getRoot(), t2.getRoot());
658 }
659
660 private:
662 {
663 if (t1 == Node::NullPtr)
664 return t2;
665
666 if (t2 == Node::NullPtr)
667 return t1;
668
669 Node *ret = Node::NullPtr;
670 const size_t m = COUNT(t1);
671 const size_t n = COUNT(t2);
672 if (const size_t rn = 1 + gsl_rng_uniform_int(r, m + n); rn <= m)
673 { // root of t1 wins
674 Node *l = LLINK(t1), *r = RLINK(t1);
675 t1->reset();
676 t1_wins:
678 if (ret != Node::NullPtr)
679 {
680 LLINK(ret) = random_join(LLINK(ret), l, dup);
681 RLINK(ret) = random_join(RLINK(ret), r, dup);
682 COUNT(ret) = COUNT(LLINK(ret)) + 1 + COUNT(RLINK(ret));
683 }
684 else
685 {
686 dup = random_insert_dup(dup, random_remove(t2, KEY(t1)));
687 goto t1_wins;
688 }
689 }
690 else
691 { // root of t2 wins
692 Node *l = LLINK(t2), *r = RLINK(t2);
693 t2->reset();
694 t2_wins:
696 if (ret != Node::NullPtr)
697 {
698 LLINK(ret) = random_join(l, LLINK(ret), dup);
699 RLINK(ret) = random_join(r, RLINK(ret), dup);
700 COUNT(ret) = COUNT(LLINK(ret)) + 1 + COUNT(RLINK(ret));
701 }
702 else
703 {
704 dup = random_insert_dup(dup, random_remove(t1, KEY(t2)));
705 goto t2_wins;
706 }
707 }
708
709 return ret;
710 }
711
713 {
714 if (t1 == Node::NullPtr)
715 return t2;
716
717 if (t2 == Node::NullPtr)
718 return t1;
719
720 Node *ret = Node::NullPtr;
721 const size_t & m = COUNT(t1);
722 const size_t & n = COUNT(t2);
723 const size_t total = m + n;
724 if (const size_t rn = 1 + gsl_rng_uniform_int(r, total); rn <= m)
725 { // root of t1 wins
726 Node *l = LLINK(t1), *r = RLINK(t1);
727 t1->reset();
731 }
732 else
733 { // root of t2 wins
734 Node *l = LLINK(t2), *r = RLINK(t2);
735 t2->reset();
739 }
740
741 COUNT(ret) = total;
742 return ret;
743 }
744
745 public:
758 void join(Gen_Rand_Tree & t, Gen_Rand_Tree & dup) noexcept
759 {
760 tree_root = random_join(tree_root, t.tree_root, dup.tree_root);
761 t.tree_root = Node::NullPtr;
762 }
763
772 void join_dup(Gen_Rand_Tree & t) noexcept
773 {
774 tree_root = random_join(tree_root, t.tree_root);
775 t.tree_root = Node::NullPtr;
776 }
777
789 void join_exclusive(Gen_Rand_Tree & t) noexcept
790 {
792 t.tree_root = Node::NullPtr;
793 }
794
801 struct Iterator : public BinNodeInfixIterator<Node>
802 {
804 };
805 };
806
841 template <typename Key, class Compare = Aleph::less<Key>>
842 struct Rand_Tree : public Gen_Rand_Tree<RandNode, Key, Compare>
843 {
845 using Base::Base;
846 };
847
848
878 template <typename Key, class Compare = Aleph::less<Key>>
879 struct Rand_Tree_Vtl : public Gen_Rand_Tree<RandNodeVtl, Key, Compare>
880 {
882 using Base::Base;
883 };
884} // end namespace Aleph
885
886# endif // TPL_RAND_TREE_H
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
void reset() noexcept
Definition htlist.H:516
__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.
constexpr Node *& RLINK(Node *p) noexcept
Return the right tree of p.
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.
constexpr Node *& LLINK(Node *p) noexcept
Return a pointer to left subtree.
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
static bool init
Definition hash-fct.C:47
DynList< T > maps(const C &c, Op op)
Classic map operation.
Iterator on nodes of the tree.
Randomized binary search tree.
Randomized binary search tree.
Binary tree operations (split, join, rotate).
Randomized tree node.
DynList< int > l