Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
dynset_trees.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
123# include <iostream>
124# include <iomanip>
125# include <chrono>
126# include <vector>
127# include <algorithm>
128# include <tclap/CmdLine.h>
129# include <tpl_dynSetTree.H>
130
131using namespace std;
132using namespace Aleph;
133
134// =============================================================================
135// Type aliases for different tree implementations
136// =============================================================================
137
138// Standard trees (no rank support)
144
145// Ranked versions (support select(i) and position(x) operations)
146// These trees maintain subtree sizes for O(log n) positional access
149
150// Note: Other ranked trees exist (Rb_Tree_Rk, Splay_Tree_Rk) but have
151// interface differences that may cause issues with DynSetTree wrapper
152
153// =============================================================================
154// Timing utilities
155// =============================================================================
156
158{
159 string name;
160 double insert_ms;
161 double search_ms;
162 double remove_ms;
163 size_t height;
165};
166
167template <typename Set>
168TimingResult benchmark_set(const string& name, const vector<int>& data,
169 bool verbose)
170{
171 TimingResult result;
172 result.name = name;
173
174 Set set;
175
176 // Benchmark insertions
177 auto start = chrono::high_resolution_clock::now();
178 for (int x : data)
179 set.insert(x);
180 auto end = chrono::high_resolution_clock::now();
181 result.insert_ms = chrono::duration<double, milli>(end - start).count();
182
183 // Get tree statistics
184 result.height = computeHeightRec(set.get_root_node());
185 result.internal_path_length = internal_path_length(set.get_root_node());
186
187 // Benchmark searches (search all elements)
188 start = chrono::high_resolution_clock::now();
189 for (int x : data)
190 {
191 auto* p = set.search(x);
192 if (p == nullptr)
193 cerr << "ERROR: element " << x << " not found!" << endl;
194 }
195 end = chrono::high_resolution_clock::now();
196 result.search_ms = chrono::duration<double, milli>(end - start).count();
197
198 // Benchmark removals
199 start = chrono::high_resolution_clock::now();
200 for (int x : data)
201 set.remove(x);
202 end = chrono::high_resolution_clock::now();
203 result.remove_ms = chrono::duration<double, milli>(end - start).count();
204
205 if (set.size() != 0)
206 cerr << "ERROR: set not empty after removals!" << endl;
207
208 if (verbose)
209 {
210 cout << " " << name << ":" << endl;
211 cout << " Height: " << result.height << endl;
212 cout << " Internal path length: " << result.internal_path_length << endl;
213 cout << " Avg path length: " << fixed << setprecision(2)
214 << (double)result.internal_path_length / data.size() << endl;
215 }
216
217 return result;
218}
219
220// =============================================================================
221// Demonstration of basic operations
222// =============================================================================
223
225{
226 cout << "=== Basic Operations Demo ===" << endl << endl;
227
228 // Using AVL tree as backend (the default)
230
231 // Insert elements
232 cout << "Inserting elements: 5, 3, 7, 1, 4, 6, 9" << endl;
233 for (int x : {5, 3, 7, 1, 4, 6, 9})
234 avl_set.insert(x);
235
236 cout << "Set size: " << avl_set.size() << endl;
237 cout << "Elements (in order): ";
238 avl_set.for_each([](int x) { cout << x << " "; });
239 cout << endl;
240
241 // Search
242 cout << endl << "Searching for 4: "
243 << (avl_set.search(4) ? "found" : "not found") << endl;
244 cout << "Searching for 8: "
245 << (avl_set.search(8) ? "found" : "not found") << endl;
246
247 // Contains
248 cout << endl << "Contains 7: " << (avl_set.contains(7) ? "yes" : "no") << endl;
249 cout << "Contains 10: " << (avl_set.contains(10) ? "yes" : "no") << endl;
250
251 // Min/Max
252 cout << endl << "Minimum: " << avl_set.min() << endl;
253 cout << "Maximum: " << avl_set.max() << endl;
254
255 // Remove
256 cout << endl << "Removing 3..." << endl;
257 avl_set.remove(3);
258 cout << "Elements after removal: ";
259 avl_set.for_each([](int x) { cout << x << " "; });
260 cout << endl;
261
262 cout << endl;
263}
264
265// =============================================================================
266// Demonstration of different tree types
267// =============================================================================
268
270{
271 cout << "=== Different Tree Types Demo ===" << endl << endl;
272
273 // Create sets with different backends
274 AvlSet avl;
275 RbSet rb;
276 SplaySet splay;
278
279 vector<int> data = {50, 25, 75, 10, 30, 60, 90, 5, 15, 27, 35};
280
281 cout << "Inserting same data into different tree types:" << endl;
282 cout << "Data: ";
283 for (int x : data) cout << x << " ";
284 cout << endl << endl;
285
286 for (int x : data)
287 {
288 avl.insert(x);
289 rb.insert(x);
290 splay.insert(x);
291 treap.insert(x);
292 }
293
294 cout << "Tree heights (lower is better balanced):" << endl;
295 cout << " AVL: " << computeHeightRec(avl.get_root_node()) << endl;
296 cout << " RB: " << computeHeightRec(rb.get_root_node()) << endl;
297 cout << " Splay: " << computeHeightRec(splay.get_root_node()) << endl;
298 cout << " Treap: " << computeHeightRec(treap.get_root_node()) << endl;
299
300 // Note: Splay tree changes structure on every access
301 cout << endl << "After searching for 5, 10, 15 (watch Splay change):" << endl;
302 splay.search(5);
303 splay.search(10);
304 splay.search(15);
305 cout << " Splay height after searches: "
306 << computeHeightRec(splay.get_root_node()) << endl;
307 cout << " (Splay moves accessed elements toward root)" << endl;
308
309 cout << endl;
310}
311
312// =============================================================================
313// Demonstration of ranked operations
314// =============================================================================
315
317{
318 cout << "=== Ranked Operations Demo ===" << endl << endl;
319
320 cout << "Ranked trees maintain subtree sizes, enabling O(log n) operations:" << endl;
321 cout << " select(i) - get i-th smallest element (0-indexed)" << endl;
322 cout << " position(x) - get rank/position of element x" << endl << endl;
323
324 cout << "Available ranked tree types:" << endl;
325 cout << " - Avl_Tree_Rk : AVL with rank (strictly balanced, deterministic)" << endl;
326 cout << " - Treap_Rk : Treap with rank (randomized balance)" << endl << endl;
327
328 // Demonstrate with ranked tree types
331
332 vector<int> data = {100, 50, 150, 25, 75, 125, 175, 10, 200};
333
334 for (int x : data)
335 {
336 avl_rk.insert(x);
337 treap_rk.insert(x);
338 }
339
340 cout << "Set contents (sorted): ";
341 avl_rk.for_each([](int x) { cout << x << " "; });
342 cout << endl << endl;
343
344 // Show select operation
345 cout << "Positional access - select(i) returns i-th element:" << endl;
346 cout << " Index AVL_Rk Treap_Rk" << endl;
347 cout << " ----- ------ --------" << endl;
348 for (size_t i = 0; i < avl_rk.size(); ++i)
349 {
350 cout << " " << i << " "
351 << setw(4) << avl_rk.select(i) << " "
352 << setw(4) << treap_rk.select(i) << endl;
353 }
354
355 // Show position operation
356 cout << endl << "Element ranks - position(x) returns index of x:" << endl;
357 cout << " Value AVL_Rk Treap_Rk" << endl;
358 cout << " ----- ------ --------" << endl;
359 for (int x : {10, 50, 100, 150, 200})
360 {
361 cout << " " << setw(3) << x << " "
362 << avl_rk.position(x) << " "
363 << treap_rk.position(x) << endl;
364 }
365
366 // Demonstrate practical use: find median
367 cout << endl << "Practical use - Finding median in O(log n):" << endl;
368 size_t mid = avl_rk.size() / 2;
369 cout << " Median (middle element): " << avl_rk.select(mid) << endl;
370
371 // Find k-th percentile
372 size_t p25 = avl_rk.size() / 4;
373 size_t p75 = 3 * avl_rk.size() / 4;
374 cout << " 25th percentile: " << avl_rk.select(p25) << endl;
375 cout << " 75th percentile: " << avl_rk.select(p75) << endl;
376
377 // Count elements less than a value
378 cout << endl << "Count elements < 100: " << avl_rk.position(100) << endl;
379
380 cout << endl;
381}
382
383// =============================================================================
384// Demonstration of functional programming features
385// =============================================================================
386
388{
389 cout << "=== Functional Programming Features ===" << endl << endl;
390
391 DynSetTree<int> set;
392 for (int i = 1; i <= 10; ++i)
393 set.insert(i);
394
395 cout << "Original set: ";
396 set.for_each([](int x) { cout << x << " "; });
397 cout << endl << endl;
398
399 // Filter: keep only even numbers
400 auto evens = set.filter([](int x) { return x % 2 == 0; });
401 cout << "Filter (even): ";
402 evens.for_each([](int x) { cout << x << " "; });
403 cout << endl;
404
405 // Map: square each element (returns DynList)
406 auto squares = set.template maps<int>([](int x) { return x * x; });
407 cout << "Map (square): ";
408 squares.for_each([](int x) { cout << x << " "; });
409 cout << endl;
410
411 // Fold: sum all elements
412 int sum = set.template foldl<int>(0, [](int acc, int x) { return acc + x; });
413 cout << "Fold (sum): " << sum << endl;
414
415 // All/Exists predicates
416 cout << endl << "Predicates:" << endl;
417 cout << " All positive? " << (set.all([](int x) { return x > 0; }) ? "yes" : "no") << endl;
418 cout << " Exists > 5? " << (set.exists([](int x) { return x > 5; }) ? "yes" : "no") << endl;
419 cout << " All <= 10? " << (set.all([](int x) { return x <= 10; }) ? "yes" : "no") << endl;
420
421 cout << endl;
422}
423
424// =============================================================================
425// Performance comparison
426// =============================================================================
427
428void run_performance_comparison(size_t n, unsigned int seed, bool verbose)
429{
430 cout << "=== Performance Comparison ===" << endl;
431 cout << "Testing with " << n << " elements (seed: " << seed << ")" << endl << endl;
432
433 if (n == 0)
434 {
435 cout << "Nothing to benchmark: n=0\n\n";
436 return;
437 }
438
439 // Generate random data
440 srand(seed);
441 vector<int> data;
442 data.reserve(n);
443 for (size_t i = 0; i < n; ++i)
444 data.push_back(rand());
445
446 // Remove duplicates (sets don't allow them)
447 sort(data.begin(), data.end());
448 data.erase(unique(data.begin(), data.end()), data.end());
449
450 if (data.empty())
451 {
452 cout << "Nothing to benchmark: all generated keys collapsed to an empty set\n\n";
453 return;
454 }
455
456 // Shuffle for random insertion order
457 for (size_t i = data.size(); i > 1; --i)
458 swap(data[i - 1], data[rand() % i]);
459
460 cout << "Actual unique elements: " << data.size() << endl << endl;
461
462 // Run benchmarks - Standard trees
464
465 cout << "Standard trees (no rank support):" << endl;
466 results.push_back(benchmark_set<AvlSet>("AVL Tree", data, verbose));
467 results.push_back(benchmark_set<RbSet>("Red-Black Tree", data, verbose));
468 results.push_back(benchmark_set<SplaySet>("Splay Tree", data, verbose));
469 results.push_back(benchmark_set<TreapSet>("Treap", data, verbose));
470 results.push_back(benchmark_set<RandSet>("Rand Tree", data, verbose));
471
472 cout << endl << "Ranked trees (with select/position support):" << endl;
473 results.push_back(benchmark_set<AvlRkSet>("AVL_Rk", data, verbose));
474 results.push_back(benchmark_set<TreapRkSet>("Treap_Rk", data, verbose));
475
476 // Print results table
477 cout << endl;
478 cout << left << setw(18) << "Tree Type"
479 << right << setw(12) << "Insert(ms)"
480 << setw(12) << "Search(ms)"
481 << setw(12) << "Remove(ms)"
482 << setw(10) << "Height"
483 << setw(15) << "Avg Path" << endl;
484 cout << string(79, '-') << endl;
485
486 for (const auto& r : results)
487 {
488 cout << left << setw(18) << r.name
489 << right << fixed << setprecision(2)
490 << setw(12) << r.insert_ms
491 << setw(12) << r.search_ms
492 << setw(12) << r.remove_ms
493 << setw(10) << r.height
494 << setw(15) << setprecision(2)
495 << (double)r.internal_path_length / data.size() << endl;
496 }
497
498 cout << endl;
499 cout << "Notes:" << endl;
500 cout << " - Height: tree height (log2(" << data.size() << ") ~= "
501 << fixed << setprecision(1) << log2(data.size()) << ")" << endl;
502 cout << " - Avg Path: average path length from root (ideal ~= log2(n))" << endl;
503 cout << " - Splay tree optimizes for access patterns, not balance" << endl;
504 cout << " - _Rk variants have slight overhead for maintaining subtree sizes" << endl;
505 cout << " - Use _Rk trees when you need select(i) or position(x) operations" << endl;
506 cout << endl;
507}
508
509// =============================================================================
510// Main
511// =============================================================================
512
513int main(int argc, char* argv[])
514{
515 try
516 {
517 TCLAP::CmdLine cmd(
518 "Demonstration of DynSetTree with different BST implementations.\n"
519 "Shows how Aleph-w allows swapping data structure implementations\n"
520 "through template parameters.",
521 ' ', "1.0");
522
523 TCLAP::ValueArg<size_t> nArg("n", "count",
524 "Number of elements for performance test",
525 false, 100000, "size_t");
526 cmd.add(nArg);
527
528 TCLAP::ValueArg<unsigned int> seedArg("s", "seed",
529 "Random seed (0 = use time)",
530 false, 0, "unsigned int");
531 cmd.add(seedArg);
532
533 TCLAP::SwitchArg allArg("a", "all",
534 "Run all demonstrations (not just performance)",
535 false);
536 cmd.add(allArg);
537
538 TCLAP::SwitchArg verboseArg("v", "verbose",
539 "Show detailed tree statistics",
540 false);
541 cmd.add(verboseArg);
542
543 cmd.parse(argc, argv);
544
545 size_t n = nArg.getValue();
546 unsigned int seed = seedArg.getValue();
547 bool runAll = allArg.getValue();
548 bool verbose = verboseArg.getValue();
549
550 if (seed == 0)
551 seed = time(nullptr);
552
553 cout << "DynSetTree - Multiple BST Implementations Demo" << endl;
554 cout << "==============================================" << endl << endl;
555
556 if (runAll)
557 {
562 }
563
565
566 cout << "Done." << endl;
567 }
568 catch (TCLAP::ArgException& e)
569 {
570 cerr << "Error: " << e.error() << " for arg " << e.argId() << endl;
571 return 1;
572 }
573
574 return 0;
575}
576
int main()
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T remove()
Remove the first item of the list.
Definition htlist.H:1611
Dynamic set backed by balanced binary search trees with automatic memory management.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
Key * search(const Key &key) const
Find an element in the set.
Node * get_root_node() const
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criteria.
Definition ah-dry.H:1135
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
void demonstrate_functional_features()
TimingResult benchmark_set(const string &name, const vector< int > &data, bool verbose)
void demonstrate_ranked_operations()
void demonstrate_tree_types()
void demonstrate_basic_operations()
void run_performance_comparison(size_t n, unsigned int seed, bool verbose)
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_log2_function > > log2(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4064
size_t internal_path_length(Node *p) noexcept
Compute the internal path length.
size_t computeHeightRec(Node *root) noexcept
Compute recursively the height of root
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Itor unique(Itor __first, Itor __last, BinaryPredicate __binary_pred=BinaryPredicate())
Remove consecutive duplicates in place.
Definition ahAlgo.H:1058
T & swap(T &t1, T &t2)
Generic swap using object's swap method.
Definition ahTypes.H:121
DynArray< T > sort(const DynArray< T > &a, Cmp &&cmp=Cmp())
Returns a sorted copy of a DynArray.
Definition ahSort.H:227
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.
size_t internal_path_length
Dynamic set implementations based on balanced binary search trees.