Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_splay_treeRk.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
48# ifndef TPL_SPLAY_TREE_RK_H
49# define TPL_SPLAY_TREE_RK_H
50
51# include <tpl_binNodeXt.H>
52# include <ah-errors.H>
53# include <ah-concepts.H>
54
55using namespace Aleph;
56
57
107template <template <class> class NodeType, typename Key, class Compare>
110{
111public:
113
114private:
116 Compare cmp;
117 static constexpr signed char CmpLess = -1;
118 static constexpr signed char CmpEqual = 0;
119 static constexpr signed char CmpGreater = 1;
120
121 signed char splay_impl(const Key & key) noexcept
122 {
123 assert(root != Node::NullPtr); // splay requires non-empty tree
124 Node header(sentinelCtor);
125 Node * head_ptr = &header;
126 Node * l = head_ptr;
127 Node * r = head_ptr;
128 Node * t = root;
129
130 size_t l_size = 0;
131 size_t r_size = 0;
132 signed char cmp_result = CmpEqual;
133
134 while (true)
135 {
136 if (const Key & tk = KEY(t); cmp(key, tk)) // key < tk: go left
137 {
139 if (LLINK(t) == Node::NullPtr) [[unlikely]]
140 break;
141
142 if (cmp(key, KEY(LLINK(t)))) // zig-zig case
143 {
144 t = rotate_to_right_xt(t);
145 if (LLINK(t) == Node::NullPtr) [[unlikely]]
146 break;
147 }
148
149 LLINK(r) = t;
150 r = t;
151 t = LLINK(t);
152 r_size += 1 + COUNT(RLINK(r));
153 }
154 else if (cmp(tk, key)) // tk < key: go right
155 {
157 if (RLINK(t) == Node::NullPtr) [[unlikely]]
158 break;
159
160 if (cmp(KEY(RLINK(t)), key)) // zig-zig case
161 {
162 t = rotate_to_left_xt(t);
163 if (RLINK(t) == Node::NullPtr) [[unlikely]]
164 break;
165 }
166
167 RLINK(l) = t;
168 l = t;
169 t = RLINK(t);
170 l_size += 1 + COUNT(LLINK(l));
171 }
172 else [[unlikely]] // key == tk: found
173 {
175 break;
176 }
177 }
178
179 l_size += COUNT(LLINK(t));
180 r_size += COUNT(RLINK(t));
181 COUNT(t) = l_size + r_size + 1;
182
183 /* reassembling of subtrees in one with t as root */
184 RLINK(l) = LLINK(t);
185 LLINK(r) = RLINK(t);
186
187 LLINK(t) = RLINK(head_ptr);
188 RLINK(t) = LLINK(head_ptr);
189
190 for (Node * y = LLINK(t); y != Node::NullPtr; y = RLINK(y))
191 {
192 COUNT(y) = l_size;
193 l_size -= 1 + COUNT(LLINK(y));
194 }
195
196 for (Node * y = RLINK(t); y != Node::NullPtr; y = LLINK(y))
197 {
198 COUNT(y) = r_size;
199 r_size -= 1 + COUNT(RLINK(y));
200 }
201
202 root = t;
203
204 return cmp_result;
205 }
206
207public:
209 typedef Key key_type;
210
212 Compare &key_comp() { return cmp; }
213
215 Compare &get_compare() { return key_comp(); }
216
222 void splay(const Key & key) noexcept
223 {
224 (void) splay_impl(key);
225 }
226
228 GenTdSplayTreeRk(Compare __cmp = Compare())
229 : root(Node::NullPtr), cmp(__cmp)
230 {
231 // Empty
232 }
233
235 {
236 std::swap(root, tree.root);
237 std::swap(cmp, tree.cmp);
238 }
239
242 { /* empty */
243 }
244
245private:
247 {
248 COUNT(p) = COUNT(root) + 1;
249 const Key & pk = KEY(p);
250 const Key & rk = KEY(root);
251 if (cmp(pk, rk))
252 {
253 COUNT(root) -= COUNT(LLINK(root));
254 LLINK(p) = LLINK(root);
255 RLINK(p) = root;
256 LLINK(root) = Node::NullPtr;
257 }
258 else
259 {
260 COUNT(root) -= COUNT(RLINK(root));
261 RLINK(p) = RLINK(root);
262 LLINK(p) = root;
263 RLINK(root) = Node::NullPtr;
264 }
265
266 return root = p; // inserted node become root
267 }
268
269public:
277 {
278 assert(p != Node::NullPtr);
279 assert(COUNT(p) == 1);
280 assert(LLINK(p) == Node::NullPtr and RLINK(p) == Node::NullPtr);
281
282 /* test insertion in empty tree */
283 if (root == Node::NullPtr)
284 return root = p;
285
286 const Key & key = KEY(p);
287
288 const signed char cmp_result = splay_impl(key);
289 if (cmp_result == CmpEqual)
290 return nullptr; // item is already in tree
291
292 return __insert(p);
293 }
294
296 {
297 assert(p != Node::NullPtr);
298 assert(LLINK(p) == Node::NullPtr and RLINK(p) == Node::NullPtr);
299
300 /* test insertion in empty tree */
301 if (root == Node::NullPtr)
302 return root = p;
303
304 splay_impl(KEY(p));
305
306 return __insert(p);
307 }
308
316 Node * search(const Key & key)
317 {
318 if (root == Node::NullPtr)
319 return nullptr;
320
321 const signed char cmp_result = splay_impl(key);
322
323 return cmp_result == CmpEqual ? root : nullptr;
324 }
325
327 {
328 if (root == Node::NullPtr)
329 return root = p;
330
331 const Key & key = KEY(p);
332 const signed char cmp_result = splay_impl(key);
333 if (cmp_result == CmpEqual)
334 return root;
335
336 return __insert(p);
337 }
338
339private:
350 Node * splay_max(Node * r) noexcept
351 {
352 if (r == Node::NullPtr || RLINK(r) == Node::NullPtr)
353 return r;
354
355 Node header(sentinelCtor);
356 Node * head_ptr = &header;
357 Node * l = head_ptr;
358 Node * t = r;
359
360 size_t l_size = 0;
361
362 // Always go right to find maximum
363 while (RLINK(t) != Node::NullPtr)
364 {
365 // Zig-zig: if grandchild exists on the right, rotate twice
366 if (RLINK(RLINK(t)) != Node::NullPtr)
367 {
368 t = rotate_to_left_xt(t);
369 if (RLINK(t) == Node::NullPtr)
370 break;
371 }
372
373 // Link left: attach t to l's right
374 RLINK(l) = t;
375 l = t;
376 t = RLINK(t);
377 l_size += 1 + COUNT(LLINK(l));
378 }
379
380 // Reassemble
381 l_size += COUNT(LLINK(t));
382 COUNT(t) = l_size + 1;
383
384 RLINK(l) = LLINK(t);
385 LLINK(t) = RLINK(head_ptr);
386
387 // Recompute counts along the left spine
388 for (Node * y = LLINK(t); y != Node::NullPtr; y = RLINK(y))
389 {
390 COUNT(y) = l_size;
391 l_size -= 1 + COUNT(LLINK(y));
392 }
393
394 return t;
395 }
396
397public:
407 Node * remove(const Key & key)
408 {
409 if (root == Node::NullPtr)
410 return nullptr;
411
412 const signed char cmp_result = splay_impl(key);
413 if (cmp_result != CmpEqual)
414 return nullptr; /* key not found */
415
416 Node *ret_val = root; /* store node to delete */
417
418 if (LLINK(root) == Node::NullPtr)
419 root = RLINK(root);
420 else if (RLINK(root) == Node::NullPtr)
421 root = LLINK(root);
422 else
423 {
425
426 // Splay the maximum of left subtree to become root.
427 // We use splay_max() instead of splay(key) because splay(key) can
428 // bring a duplicate that is not the actual maximum, corrupting counts.
429 // splay_max() uses proper zig-zig rotations to maintain O(log n) amortized.
431
432 // The new root has no right child (it was the maximum)
433 // Connect the right subtree
436 }
437
438 ret_val->reset();
439
440 return ret_val;
441 }
442
445 {
446 return root;
447 }
448
449 bool verify() const { return check_rank_tree(root) and check_bst(root, cmp); }
450
452 size_t size() const
453 {
454 return COUNT(root);
455 }
456
458 bool is_empty() const
459 {
460 return root == Node::NullPtr;
461 }
462
474 std::pair<long, Node *> position(const Key & key)
475 {
476 if (root == Node::NullPtr)
477 return {-1, nullptr};
478
479 const signed char cmp_result = splay_impl(key);
480 if (cmp_result == CmpEqual)
481 return {static_cast<long>(COUNT(LLINK(root))), root};
482
483 return {-1, nullptr};
484 }
485
513 std::pair<long, Node *> find_position(const Key & key)
514 {
515 if (root == Node::NullPtr)
516 return {-1, nullptr};
517
518 const signed char cmp_result = splay_impl(key);
519 if (cmp_result == CmpEqual)
520 return {static_cast<long>(COUNT(LLINK(root))), root};
521
522 // key not found - determine position it would have
523 if (cmp_result == CmpLess)
524 return {static_cast<long>(COUNT(LLINK(root))) - 1, root}; // less than root
525 return {static_cast<long>(COUNT(LLINK(root))) + 1, root};
526 // greater than root
527 }
528
539 Node * select(const size_t & i)
540 {
541 return Aleph::select(root, i);
542 }
543
549 {
551 Node *curr = Node::NullPtr;
552 size_t pos = 0;
553
554 public:
555 Iterator() = default;
556
558 : tree_ptr(&tree), curr(Node::NullPtr), pos(0)
559 {
560 if (tree_ptr->root != Node::NullPtr)
562 }
563
564 bool has_curr() const noexcept { return curr != Node::NullPtr; }
565
566 Node * get_curr() const
567 {
568 ah_overflow_error_if(curr == Node::NullPtr)
569 << "Iterator is at end";
570 return curr;
571 }
572
574
575 void next()
576 {
577 ah_overflow_error_if(curr == Node::NullPtr)
578 << "Iterator is at end";
580 ++pos;
581 }
582
584 {
586 ++pos;
587 }
588
589 size_t get_pos() const noexcept { return pos; }
590
592 {
593 pos = 0;
594 if (tree_ptr != nullptr && tree_ptr->root != Node::NullPtr)
596 else
597 curr = Node::NullPtr;
598 }
599
600 private:
601 static Node * find_min(Node *r) noexcept
602 {
603 while (LLINK(r) != Node::NullPtr)
604 r = LLINK(r);
605 return r;
606 }
607
608 static Node * inorder_successor(Node *root, const Key & key) noexcept
609 {
610 Node *successor = Node::NullPtr;
611 Node *curr = root;
612
613 while (curr != Node::NullPtr)
614 {
615 if (key < KEY(curr))
616 {
617 successor = curr;
618 curr = LLINK(curr);
619 }
620 else
621 curr = RLINK(curr);
622 }
623
624 return successor;
625 }
626 };
627};
628
629
630template <typename Key, class Compare = Aleph::less<Key>>
632struct Splay_Tree_Rk : public GenTdSplayTreeRk<BinNodeXt, Key, Compare>
633{
635 using Base::Base;
636};
637
638
639template <typename Key, class Compare = Aleph::less<Key>>
641struct Splay_Tree_Rk_Vtl : public GenTdSplayTreeRk<BinNodeXtVtl, Key, Compare>
642{
644 using Base::Base;
645};
646
647
648#endif /* TPL_SPLAY_TREE_RK_H */
C++20 concepts for constraining comparison functors.
Exception handling system with formatted messages for Aleph-w.
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
@ sentinelCtor
Definition ahDefs.H:81
@ KEY
Definition btreepic.C:169
Inorder iterator over the extended splay tree.
size_t get_pos() const noexcept
Node * get_curr_ne() const noexcept
static Node * find_min(Node *r) noexcept
Iterator(GenTdSplayTreeRk &tree) noexcept
bool has_curr() const noexcept
static Node * inorder_successor(Node *root, const Key &key) noexcept
Top-down splay tree with rank support.
std::pair< long, Node * > position(const Key &key)
Returns the inorder (sorted) position of key.
Node * splay_max(Node *r) noexcept
Splay the maximum element to the root.
GenTdSplayTreeRk(Compare __cmp=Compare())
Constructor.
void splay(const Key &key) noexcept
search key within tree and splay that node.
Compare & get_compare()
static constexpr signed char CmpGreater
void swap(GenTdSplayTreeRk &tree)
std::pair< long, Node * > find_position(const Key &key)
Returns the inorder (sorted) position of key.
Node * insert(Node *p)
Inserts a node in a top down splay tree.
NodeType< Key > Node
Compare & key_comp()
Returns a reference to the comparison functor.
Node * remove(const Key &key)
Remove a key from a top-down splay tree.
Node * search_or_insert(Node *p)
bool is_empty() const
Returns true if the tree is empty.
signed char splay_impl(const Key &key) noexcept
Node * search(const Key &key)
Searches a key in a top down splay tree.
Node * __insert(Node *p)
static constexpr signed char CmpEqual
Key key_type
The key type stored in the node.
Node * select(const size_t &i)
Returns the node whose inorder position in the extended tree is i.
Node * insert_dup(Node *p)
virtual ~GenTdSplayTreeRk()
Destructor.
static constexpr signed char CmpLess
size_t size() const
Returns the number of nodes stored in the tree.
Node *& getRoot()
Get the top-down splay tree's root.
bool check_rank_tree(Node *root) noexcept
Return true if root is a valid extended binary tree.
bool check_bst(Node *p, const Compare &cmp=Compare())
Return true if p is a binary search tree.
auto & COUNT(Node *p) noexcept
Return the number of nodes of the tree fron p is root.
Node * rotate_to_left_xt(Node *p) noexcept
Rotate to left the extended binary tree with root p.
Node * select(Node *r, const size_t pos)
Iterative selection of a node according to inorder position.
Node * rotate_to_right_xt(Node *p) noexcept
Rotate to right the extended bianry tree with root p
static mpfr_t y
Definition mpfr_mul_d.c:3
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 RLINK(i, n)
#define LLINK(i, n)
gsl_rng * r
Extended binary node with subtree count.
DynList< int > l