Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_skipList.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
51# ifndef TPL_SKIPLIST_H
52# define TPL_SKIPLIST_H
53
54# include <climits>
55# include <ctime>
56# include <gsl/gsl_rng.h>
57# include <aleph.H>
58# include <ah-errors.H>
59
60namespace Aleph
61{
92 template <class Key, class Type>
94 {
95 public:
97 static const int maxLevel = 32;
98
100 static const double defaultProbability;
101
102 class Node
103 {
104 protected:
105 int level;
106
108
109 /*
110 Public methods work in function of nullptr pointer in order to indicate
111 unsuccessful conditions. We put NullPtr as private in order to avoid
112 that to accidentally put NullPtr instead of nullptr
113 */
114 static Node *NullPtr;
115
116 private:
117 Key key;
119
121 {
122 return reinterpret_cast<Node **>(reinterpret_cast<char *>(this) + sizeof(*this));
123 }
124
126 {
127 return reinterpret_cast<Node * const *>(
128 reinterpret_cast<const char *>(this) + sizeof(*this));
129 }
130
132 {
133 for (int i = 0; i < level; i++)
134 forward_ptr()[i] = const_cast<Node *>(&nodeSentinel);
135 }
136
137 public:
138 friend class SkipList<Key, Type>;
139
140 Node(const Key & _key, const Type & _data, int n)
141 : level(n),
142 key(_key),
143 data(_data)
144 {
145 /* EMPTY */
146 }
147
148 Node(const Key & _key, int n)
149 : level(n),
150 key(_key)
151 {
152 /* EMPTY */
153 }
154
155 Node(const int n)
156 : level(n)
157 {
158 /* EMPTY */
159 }
160
162 : level(0),
164 {
165 /* EMPTY */
166 }
167
168 ~Node() = default;
169
171 {
172 auto *next = forward_ptr()[0];
173 return (next == NullPtr) ? nullptr : next;
174 }
175
177 {
178 assert(i < level);
179 return forward_ptr()[i];
180 }
181
183 {
184 return forward_ptr();
185 }
186
187 [[nodiscard]] const Key &get_key() const noexcept { return key; }
188
189 Key &get_key() noexcept { return key; }
190
191 [[nodiscard]] const Type &get_data() const noexcept { return data; }
192
193 Type &get_data() noexcept { return data; }
194
195 [[nodiscard]] int getLevel() const noexcept { return level; }
196
200
201 protected:
203 };
204
205 private:
206 /*
207 Headenode : it's used for header node,
208 it's an static array with maxLevel elements
209 */
211 {
212 private:
214
215 friend class SkipList<Key, Type>;
216
217 public:
219 {
220 this->level = maxLevel;
221
222 for (int i = 0; i < maxLevel; i++)
223 HeaderNode::forward[i] = Node::NullPtr;
224 }
225
227 {
229 assert(this->getLevel() <= maxLevel);
230
231 return HeaderNode::forward[i];
232 }
233 };
234
235 /*
236 Node*& getForward(Node* p, int i)
237 {
238 if ( p == headerPtr )
239 return ((HeaderNode*) p)->HeaderNode::forward[ i ];
240 else
241 return p->Node::forward[ i ];
242 }
243 */
244
245 HeaderNode header; // SkipList's header
246 HeaderNode *headerPtr; // Pointer to header
247 gsl_rng *r; // GSL random number generator
248 double probability; // probability for randomLevel
249 int level; // Current Maximum level of list linked
250
251
252 void init(unsigned long seed)
253 {
255 ah_bad_alloc_if(r == nullptr);
256 gsl_rng_set(r, seed % gsl_rng_max(r));
257 }
258
259 public:
261 void set_seed(unsigned long seed) noexcept { gsl_rng_set(r, seed); }
262
265
270 SkipList(unsigned long seed, double p = defaultProbability)
271 : headerPtr(&header),
272 r(nullptr),
273 probability(p),
274 level(0)
275 {
277 init(seed);
278 }
279
283 explicit SkipList(double p = defaultProbability)
284 : SkipList(time(nullptr), p)
285 {
286 // Empty
287 }
288
291 {
292 if (r != nullptr)
294 }
295
296 // Disable copy (owns GSL resource)
297 SkipList(const SkipList &) = delete;
298 SkipList & operator=(const SkipList &) = delete;
299
300 // Move constructor
302 : header(std::move(other.header)),
304 r(other.r),
305 probability(other.probability),
306 level(other.level)
307 {
308 other.r = nullptr;
309 other.level = 0;
310 }
311
312 // Move assignment
314 {
315 if (this != &other)
316 {
317 if (r != nullptr)
319 header = std::move(other.header);
320 headerPtr = &header;
321 r = other.r;
322 probability = other.probability;
323 level = other.level;
324 other.r = nullptr;
325 other.level = 0;
326 }
327 return *this;
328 }
329
334 [[nodiscard]] Node * search(const Key & searchKey) noexcept
335 {
336 Node *x = headerPtr;
337
338 for (int i = level - 1; i >= 0; i--)
339 while (x->getForward(i)->get_key() < searchKey)
340 x = x->getForward(i);
341
342 x = x->getForward(0);
343
344 // Return nullptr if not found (either sentinel or different key)
345 if (x == Node::NullPtr || x->get_key() != searchKey)
346 return nullptr;
347
348 return x;
349 }
350
356 Node * insert(Node *p) noexcept
357 {
358 int i;
359 Node *update[maxLevel];
360 Node *x = headerPtr;
361
362 assert(p->getLevel() > 0 and p->getLevel() <= maxLevel);
363
364 p->fillForwardnullptr();
365
366 for (i = level - 1; i >= 0; i--)
367 {
368 while (x->getForward(i)->get_key() < p->get_key())
369 x = x->getForward(i);
370
371 update[i] = x;
372 }
373
374 x = x->getForward(0); // go to next node
375
376 if (p->getLevel() > level)
377 {
378 for (i = level; i < p->getLevel(); i++)
379 update[i] = headerPtr;
380 level = p->getLevel();
381 }
382
383
384 for (i = 0; i < p->getLevel(); i++)
385 {
386 p->getForward(i) = update[i]->getForward(i);
387 update[i]->getForward(i) = p;
388 }
389
390 assert(checkSkipList() == true);
391 return p;
392 }
393
397 {
398 return headerPtr->HeaderNode::forward[0];
399 }
400
406 [[nodiscard]] Node * remove(const Key & searchKey) noexcept
407 {
408 Node *update[maxLevel];
409 Node *x = headerPtr;
410 int i;
411
412 for (i = level - 1; i >= 0; i--)
413 {
414 while (x->getForward(i)->get_key() < searchKey)
415 x = x->getForward(i);
416 update[i] = x;
417 }
418
419 x = x->getForward(0);
420
421 if (x->get_key() == searchKey)
422 {
423 for (i = 0; i < level; i++)
424 {
425 if (update[i]->getForward(i) != x)
426 break;
427 update[i]->getForward(i) = x->getForward(i);
428 }
429
430 while (level > 0 and headerPtr->getForward(level) == nullptr)
431 level--;
432 }
433 else
434 return nullptr;
435
436 assert(checkSkipList() == true);
437
438 return x;
439 }
440
446 {
447 int l = 1;
450 ++l;
451 return l;
452 }
453
458 {
459 Node *node = header.get_next();
460 while (node != nullptr)
461 {
462 if (node->get_next() == nullptr)
463 break;
464
465 if (node->get_key() > node->get_next()->get_key())
466 return false;
467 node = node->get_next();
468 }
469 return true;
470 }
471
473 [[nodiscard]] Node * new_node() noexcept { return nullptr; }
474
488 {
489 const SkipList *list_ptr = nullptr;
490 Node *curr = nullptr;
491
492 public:
494
496 Iterator() noexcept = default;
497
498 Iterator(const Iterator &) noexcept = default;
499
502 Iterator(const SkipList & list) noexcept
503 : list_ptr(&list), curr(list.headerPtr->HeaderNode::forward[0])
504 {
505 // Skip sentinel if we landed on it
506 if (curr == Node::NullPtr)
507 curr = nullptr;
508 }
509
512 [[nodiscard]] bool has_curr() const noexcept { return curr != nullptr; }
513
515 [[nodiscard]] bool is_last() const noexcept
516 {
517 if (curr == nullptr)
518 return false;
519 Node *next = curr->get_next();
520 return next == nullptr;
521 }
522
526 [[nodiscard]] Node * get_curr() const
527 {
528 ah_overflow_error_if(curr == nullptr) << "SkipList::Iterator::get_curr(): no current";
529
530 return curr;
531 }
532
535 [[nodiscard]] Node * get_curr_ne() const noexcept { return curr; }
536
538 [[nodiscard]] const Key &get_key() const { return get_curr()->get_key(); }
539
541 [[nodiscard]] const Type &get_data() const { return get_curr()->get_data(); }
542
544 void next()
545 {
546 ah_overflow_error_if(curr == nullptr) << "SkipList::Iterator::next(): no current";
547 next_ne();
548 }
549
551 void next_ne() noexcept
552 {
553 if (curr != nullptr)
554 {
555 curr = curr->get_next();
556 // get_next() returns nullptr for sentinel, so we're done
557 }
558 }
559
561 void reset_first() noexcept
562 {
563 if (list_ptr != nullptr)
564 {
565 curr = list_ptr->headerPtr->HeaderNode::forward[0];
566 if (curr == Node::NullPtr)
567 curr = nullptr;
568 }
569 }
570
572 void reset() noexcept { reset_first(); }
573
575 Iterator &operator=(const Iterator & it) noexcept
576 {
577 list_ptr = it.list_ptr;
578 curr = it.curr;
579 return *this;
580 }
581
583 [[nodiscard]] bool operator==(const Iterator & it) const noexcept
584 {
585 return curr == it.curr;
586 }
587
589 [[nodiscard]] bool operator!=(const Iterator & it) const noexcept
590 {
591 return curr != it.curr;
592 }
593
596 {
597 next_ne();
598 return *this;
599 }
600
602 Iterator operator++(int) noexcept
603 {
604 Iterator ret = *this;
605 next_ne();
606 return ret;
607 }
608
610 [[nodiscard]] Node * operator*() const { return get_curr(); }
611
613 [[nodiscard]] Node * operator->() const { return get_curr(); }
614 };
615
618
621 };
622
623 /*
624 BEWARE: Ensure that this instantiation to be unique
625 */
626 template <class Key, class Type>
627 typename SkipList<Key, Type>::Node SkipList<Key, Type>::Node::nodeSentinel;
628
629 template <class Key, class Type>
630 typename SkipList<Key, Type>::Node *SkipList<Key, Type>::Node::NullPtr =
631 &SkipList<Key, Type>::Node::nodeSentinel;
632
633
634 template <class Key, class Type>
636} // end namespace Aleph
637
638# endif // TPL_SKIPLIST_H
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
#define ah_bad_alloc_if(C)
Throws std::bad_alloc if condition holds.
Definition ah-errors.H:429
Core header for the Aleph-w library.
SkipList< Key, Type >::Node * forward[maxLevel]
Iterator for traversing SkipList elements in ascending order.
const Type & get_data() const
Get current data (throws if no current).
Node * operator->() const
Arrow operator (returns node pointer).
Iterator & operator=(const Iterator &it) noexcept
Assignment operator.
bool is_last() const noexcept
Check if iterator is on the last element.
Iterator operator++(int) noexcept
Postfix increment operator.
bool operator==(const Iterator &it) const noexcept
Equality comparison.
Iterator() noexcept=default
Default constructor (invalid iterator).
void next_ne() noexcept
Advance to next element without exception check.
Node * get_curr() const
Get current node (throws if no current).
Node * operator*() const
Dereference operator (returns node pointer).
Iterator & operator++() noexcept
Prefix increment operator.
bool has_curr() const noexcept
Check if iterator has a current element.
void next()
Advance to next element (throws if no current).
void reset_first() noexcept
Reset iterator to first element.
Node * get_curr_ne() const noexcept
Get current node without exception check.
const Key & get_key() const
Get current key (throws if no current).
void reset() noexcept
Reset iterator to first element (alias).
bool operator!=(const Iterator &it) const noexcept
Inequality comparison.
Node(const Key &_key, const Type &_data, int n)
Node(const Key &_key, int n)
Node * get_next() const noexcept
Node *& getForward(int i)
Key & get_key() noexcept
const Key & get_key() const noexcept
int getLevel() const noexcept
Node ** forward_ptr() noexcept
static Key computeMaxKey() noexcept
Compute the maximum possible key value (used for sentinel).
Node *const * forward_ptr() const noexcept
static Node * NullPtr
Type & get_data() noexcept
const Type & get_data() const noexcept
Skip List - a probabilistic ordered data structure.
~SkipList()
Destructor - frees GSL random number generator.
void set_seed(unsigned long seed) noexcept
Set the random number generator seed.
Node * get_first() noexcept
Get the first node in the list.
bool checkSkipList() const noexcept
Verify skip list invariants (for debugging).
Node * remove(const Key &searchKey) noexcept
Remove a key from the skip list.
static const int maxLevel
Maximum level for any node (supports up to 2^32 elements efficiently)
int generateRandomLevel() noexcept
Generate a random level for a new node.
void init(unsigned long seed)
Iterator begin() const noexcept
Get iterator to first element.
SkipList & operator=(SkipList &&other) noexcept
SkipList(const SkipList &)=delete
Node * search(const Key &searchKey) noexcept
Search for a key in the skip list.
HeaderNode * headerPtr
static const double defaultProbability
Default probability for level generation (0.5 = geometric distribution)
Iterator end() const noexcept
Get iterator past the last element.
SkipList(SkipList &&other) noexcept
SkipList(double p=defaultProbability)
Construct a SkipList with time-based seed.
SkipList(unsigned long seed, double p=defaultProbability)
Construct a SkipList with given seed and probability.
Node * new_node() noexcept
Placeholder for node allocation (override in derived classes).
HeaderNode header
Node * insert(Node *p) noexcept
Insert a node into the skip list.
gsl_rng * gsl_rng_object() noexcept
Get a pointer to the GSL random number generator.
SkipList & operator=(const SkipList &)=delete
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void next_ne() noexcept
Advance all underlying iterators (no-throw variant).
Definition ah-zip.H:185
auto get_curr() const
Return the current tuple (bounds-checked).
Definition ah-zip.H:149
static bool init
Definition hash-fct.C:47
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
DynList< T > maps(const C &c, Op op)
Classic map operation.
DynList< int > l