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