Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
skiplist_example.C
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
192#include <iostream>
193#include <iomanip>
194#include <string>
195#include <chrono>
196#include <random>
197#include <vector>
198#include <set>
199#include <tpl_dynSkipList.H>
200#include <tclap/CmdLine.h>
201
202using namespace std;
203using namespace Aleph;
204
212{
213 cout << "\n=== Basic Skip List Operations ===" << endl;
214
215 // Create a skip list set of integers
216 DynSkipList<int> skiplist;
217
218 // Insert elements
219 cout << "\nInserting elements..." << endl;
220 vector<int> data = {42, 17, 99, 23, 8, 64, 31, 55, 100, 5};
221
222 for (int val : data)
223 {
224 skiplist.insert(val);
225 cout << " Inserted: " << val << endl;
226 }
227
228 cout << "\nSkip list size: " << skiplist.size() << endl;
229
230 // Search operations
231 cout << "\n--- Search Operations ---" << endl;
232
233 vector<int> search_keys = {23, 100, 42, 0, 50};
234 for (int key : search_keys)
235 {
236 auto* found = skiplist.search(key);
237 cout << " search(" << key << "): ";
238 if (found)
239 cout << "Found!" << endl;
240 else
241 cout << "Not found" << endl;
242 }
243
244 // has() convenience method
245 cout << "\nUsing has() method:" << endl;
246 cout << " has(42): " << (skiplist.has(42) ? "yes" : "no") << endl;
247 cout << " has(50): " << (skiplist.has(50) ? "yes" : "no") << endl;
248
249 // Traversal (sorted order)
250 cout << "\n--- Sorted Traversal ---" << endl;
251 cout << "Elements in ascending order:" << endl;
252 cout << " ";
253
254 for (auto it = skiplist.get_it(); it.has_curr(); it.next())
255 cout << it.get_curr() << " ";
256 cout << endl;
257
258 // Removal
259 cout << "\n--- Removal Operations ---" << endl;
260
261 cout << "Removing 23..." << endl;
262 size_t removed_count = skiplist.remove(23);
263 cout << " Removed " << removed_count << " element(s)" << endl;
264
265 cout << "Trying to remove non-existent 1000..." << endl;
266 removed_count = skiplist.remove(1000);
267 cout << " Removed " << removed_count << " element(s)" << endl;
268
269 cout << "\nFinal size: " << skiplist.size() << endl;
270 cout << "Final elements: ";
271 for (auto it = skiplist.get_it(); it.has_curr(); it.next())
272 cout << it.get_curr() << " ";
273 cout << endl;
274}
275
280{
281 cout << "\n=== Skip List with Strings ===" << endl;
282
284
285 // Add words
287 "algorithm", "binary", "complexity", "data", "efficient",
288 "function", "graph", "hash", "index", "join"
289 };
290
291 cout << "Building vocabulary..." << endl;
292 for (const auto& word : vocabulary)
293 words.insert(word);
294
295 // Display in sorted (alphabetical) order
296 cout << "\nWords in alphabetical order:" << endl;
297 for (auto it = words.get_it(); it.has_curr(); it.next())
298 cout << " " << it.get_curr() << endl;
299
300 // Search for words
301 cout << "\nSearching:" << endl;
302 cout << " 'complexity' exists: " << (words.has("complexity") ? "yes" : "no") << endl;
303 cout << " 'hello' exists: " << (words.has("hello") ? "yes" : "no") << endl;
304}
305
310{
311 cout << "\n=== Functional Programming with Skip Lists ===" << endl;
312
314 for (int i = 1; i <= 20; i++)
315 numbers.insert(i * 3); // Multiples of 3: 3, 6, 9, ..., 60
316
317 cout << "Numbers (multiples of 3 up to 60):" << endl;
318 cout << " ";
319 numbers.for_each([](int n) { cout << n << " "; });
320 cout << endl;
321
322 // All / Exists predicates
323 cout << "\nPredicates:" << endl;
324 cout << " all > 0: " << (numbers.all([](int n) { return n > 0; }) ? "true" : "false") << endl;
325 cout << " exists 30: " << (numbers.exists([](int n) { return n == 30; }) ? "true" : "false") << endl;
326 cout << " exists 31: " << (numbers.exists([](int n) { return n == 31; }) ? "true" : "false") << endl;
327
328 // Fold
329 int sum = numbers.template foldl<int>(0, [](int acc, int n) { return acc + n; });
330 cout << "\nSum of all elements: " << sum << endl;
331 cout << "Expected sum (3+6+...+60): " << (3 * 20 * 21 / 2) << endl;
332}
333
337void benchmark_comparison(size_t n, unsigned seed, bool verbose)
338{
339 cout << "\n=== Performance Benchmark ===" << endl;
340 cout << "Comparing DynSkipList vs std::set with " << n << " elements" << endl;
341
342 // Generate random keys
343 mt19937 rng(seed);
344 uniform_int_distribution<int> dist(0, static_cast<int>(n) * 10);
345
346 vector<int> keys(n);
347 for (size_t i = 0; i < n; i++)
348 keys[i] = dist(rng);
349
350 // Search keys (mix of existing and non-existing)
351 vector<int> search_keys(n / 10);
352 for (size_t i = 0; i < search_keys.size(); i++)
353 search_keys[i] = (i % 2 == 0) ? keys[i * 10 % n] : dist(rng);
354
355 // Benchmark DynSkipList
356 DynSkipList<int> skiplist;
357
358 auto start = chrono::high_resolution_clock::now();
359 for (int key : keys)
360 skiplist.insert(key);
361 auto end = chrono::high_resolution_clock::now();
362 double skiplist_insert = chrono::duration<double, milli>(end - start).count();
363
364 start = chrono::high_resolution_clock::now();
365 int skiplist_found = 0;
366 for (int key : search_keys)
367 if (skiplist.has(key)) skiplist_found++;
368 end = chrono::high_resolution_clock::now();
369 double skiplist_search = chrono::duration<double, milli>(end - start).count();
370
371 // Benchmark std::set
373
374 start = chrono::high_resolution_clock::now();
375 for (int key : keys)
376 stdset.insert(key);
377 end = chrono::high_resolution_clock::now();
378 double stdset_insert = chrono::duration<double, milli>(end - start).count();
379
380 start = chrono::high_resolution_clock::now();
381 int stdset_found = 0;
382 for (int key : search_keys)
383 if (stdset.find(key) != stdset.end()) stdset_found++;
384 end = chrono::high_resolution_clock::now();
385 double stdset_search = chrono::duration<double, milli>(end - start).count();
386
387 // Results
388 cout << "\n" << setw(15) << "Operation"
389 << setw(18) << "DynSkipList (ms)"
390 << setw(18) << "std::set (ms)"
391 << setw(12) << "Ratio" << endl;
392 cout << string(63, '-') << endl;
393
394 cout << setw(15) << "Insert " << n
395 << setw(18) << fixed << setprecision(3) << skiplist_insert
396 << setw(18) << stdset_insert
397 << setw(12) << setprecision(2) << skiplist_insert / stdset_insert << "x" << endl;
398
399 cout << setw(15) << "Search " << search_keys.size()
400 << setw(18) << fixed << setprecision(3) << skiplist_search
401 << setw(18) << stdset_search
402 << setw(12) << setprecision(2) << skiplist_search / stdset_search << "x" << endl;
403
404 if (verbose)
405 {
406 cout << "\nDynSkipList found: " << skiplist_found << "/" << search_keys.size() << endl;
407 cout << "std::set found: " << stdset_found << "/" << search_keys.size() << endl;
408 cout << "DynSkipList size: " << skiplist.size() << " (unique elements)" << endl;
409 cout << "std::set size: " << stdset.size() << " (unique elements)" << endl;
410 }
411
412 cout << "\nNote: Skip Lists trade some raw performance for:" << endl;
413 cout << " - Simpler implementation (no rotations)" << endl;
414 cout << " - Easier concurrent access" << endl;
415 cout << " - Ordered iteration for range scans" << endl;
416}
417
422{
423 cout << "\n=== Skip List Structure Visualization ===" << endl;
424 cout << "\nConceptual view of a skip list with keys 3, 6, 7, 9, 12, 17, 19, 21:" << endl;
425 cout << endl;
426 cout << " Level 3: HEAD ---------------------------------> 12 ---------------------------------> NIL" << endl;
427 cout << " Level 2: HEAD ----------------> 6 ------------> 12 ----------------> 19 ------------> NIL" << endl;
428 cout << " Level 1: HEAD --------> 3 ----> 6 ----> 9 ----> 12 ----> 17 -------> 19 ----> 21 ----> NIL" << endl;
429 cout << " Level 0: HEAD -> 3 -> 6 -> 7 -> 9 -> 12 -> 17 -> 19 -> 21 -> NIL" << endl;
430 cout << endl;
431
432 cout << "Search for 17:" << endl;
433 cout << " 1. Start at HEAD, Level 3" << endl;
434 cout << " 2. 12 < 17, move right to 12" << endl;
435 cout << " 3. 12 -> NIL, drop to Level 2" << endl;
436 cout << " 4. 19 > 17, drop to Level 1" << endl;
437 cout << " 5. 17 = 17, FOUND!" << endl;
438 cout << "\nSteps: ~4 (vs 6 for linear search)" << endl;
439
440 cout << "\nKey insight: Higher levels act as 'express lanes'" << endl;
441 cout << "Expected levels per node: log(n) with p=0.5" << endl;
442}
443
444int main(int argc, char* argv[])
445{
446 try
447 {
448 TCLAP::CmdLine cmd("Skip List Example", ' ', "1.0");
449
450 TCLAP::SwitchArg basicArg("b", "basic",
451 "Show basic operations demo", false);
452 TCLAP::SwitchArg stringArg("s", "string",
453 "Show string set demo", false);
454 TCLAP::SwitchArg funcArg("f", "functional",
455 "Show functional programming demo", false);
456 TCLAP::SwitchArg benchArg("p", "benchmark",
457 "Run performance benchmark", false);
458 TCLAP::SwitchArg visArg("i", "visualize",
459 "Visualize skip list structure", false);
460 TCLAP::ValueArg<size_t> sizeArg("n", "size",
461 "Number of elements for benchmark", false, 100000, "size_t");
462 TCLAP::ValueArg<unsigned> seedArg("r", "seed",
463 "Random seed", false, 42, "unsigned");
464 TCLAP::SwitchArg verboseArg("v", "verbose",
465 "Show detailed output", false);
466 TCLAP::SwitchArg allArg("a", "all",
467 "Run all demos", false);
468
469 cmd.add(basicArg);
470 cmd.add(stringArg);
471 cmd.add(funcArg);
472 cmd.add(benchArg);
473 cmd.add(visArg);
474 cmd.add(sizeArg);
475 cmd.add(seedArg);
476 cmd.add(verboseArg);
477 cmd.add(allArg);
478
479 cmd.parse(argc, argv);
480
481 bool runBasic = basicArg.getValue();
482 bool runString = stringArg.getValue();
483 bool runFunc = funcArg.getValue();
484 bool runBench = benchArg.getValue();
485 bool runVis = visArg.getValue();
486 bool runAll = allArg.getValue();
487 size_t size = sizeArg.getValue();
488 unsigned seed = seedArg.getValue();
489 bool verbose = verboseArg.getValue();
490
491 // Default: run all if nothing specified
492 if (!runBasic && !runString && !runFunc && !runBench && !runVis)
493 runAll = true;
494
495 cout << "=== Skip List: Probabilistic Data Structure ===" << endl;
496 cout << "Invented by William Pugh (1990)" << endl;
497
498 if (runAll || runVis)
500
501 if (runAll || runBasic)
503
504 if (runAll || runString)
506
507 if (runAll || runFunc)
509
510 if (runAll || runBench)
512
513 cout << "\n=== Complexity Summary ===" << endl;
514 cout << "Search: O(log n) expected" << endl;
515 cout << "Insert: O(log n) expected" << endl;
516 cout << "Delete: O(log n) expected" << endl;
517 cout << "Space: O(n) expected" << endl;
518
519 return 0;
520 }
521 catch (TCLAP::ArgException& e)
522 {
523 cerr << "Error: " << e.error() << " for arg " << e.argId() << endl;
524 return 1;
525 }
526}
int main()
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
bool has_curr() const noexcept
Dynamic ordered set implemented with a Skip List.
size_t remove(const Key &key)
Remove a key from the set.
Iterator get_it() const noexcept
Alias for begin() - for generic programming.
Key * insert(const Key &key)
Insert an element into the set.
size_t size() const noexcept
Return the number of elements in the set.
bool has(const Key &key) const noexcept
Return true if the key exists in the set.
Key * search(const Key &key) const noexcept
Search for a key in the set.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
bool exists(Operation &op) const
Test for existence in the container of an element satisfying a criteria.
Definition ah-dry.H:846
bool all(Operation &operation) const
Check if all the elements of container satisfy a condition.
Definition ah-dry.H:816
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:685
iterator end() noexcept
Return an STL-compatible end iterator.
static mt19937 rng
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t size(Node *root) noexcept
bool verbose
Flag enabling verbose output.
Definition ahDefs.C:45
DynList< T > maps(const C &c, Op op)
Classic map operation.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
STL namespace.
void visualize_structure()
Visualize skip list structure (small example)
void demonstrate_string_set()
Demonstrate skip list with strings.
void demonstrate_basic_operations()
Demonstrate basic Skip List operations.
void demonstrate_functional()
Demonstrate functional programming features.
void benchmark_comparison(size_t n, unsigned seed, bool verbose)
Benchmark skip list vs std::set.
Dynamic ordered set implemented with a Skip List.