Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
hash_tables_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
207#include <iostream>
208#include <string>
209#include <chrono>
210#include <random>
211#include <iomanip>
212
213#include <tpl_dynSetHash.H>
214#include <tpl_odhash.H>
215
216using namespace std;
217using namespace Aleph;
218
219static void print_usage(const char* prog)
220{
221 cout << "Usage: " << prog << " [-s <chaining|linear|open|performance|all>] [--help]\n";
222 cout << "\nIf no selector is given, all demos are executed.\n";
223}
224
225// =============================================================================
226// Example 1: DynSetLhash - Separate Chaining
227// =============================================================================
228
230{
231 cout << "\n";
232 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
233 cout << "║ EXAMPLE 1: DynSetLhash (Separate Chaining) ║\n";
234 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
235
236 cout << "DynSetLhash uses linked lists to handle collisions.\n";
237 cout << "Each bucket is a list of entries with the same hash.\n\n";
238
240
241 // Insert values
242 vector<int> values = {10, 20, 30, 40, 50, 60, 70, 80};
243
244 cout << "Inserting values:\n";
245 for (int v : values) {
246 set.insert(v);
247 cout << " ✓ " << v << "\n";
248 }
249
250 cout << "\nSet size: " << set.size() << "\n";
251
252 cout << "\n--- Membership testing ---\n\n";
253
254 auto test_contains = [&](int key) {
255 bool found = set.contains(key);
256 cout << " contains(" << key << "): " << (found ? "YES" : "NO") << "\n";
257 };
258
259 test_contains(30);
260 test_contains(50);
261 test_contains(100);
262 test_contains(70);
263
264 cout << "\n--- Removal ---\n\n";
265
266 cout << "Removing 40...\n";
267 set.remove(40);
268
269 cout << "Removing 70...\n";
270 set.remove(70);
271
272 test_contains(40);
273 test_contains(70);
274
275 cout << "\nFinal size: " << set.size() << "\n";
276
277 cout << "\n--- Iteration ---\n\n";
278 cout << "All elements: ";
279 set.for_each([](const int& v) { cout << v << " "; });
280 cout << "\n";
281}
282
283// =============================================================================
284// Example 2: DynSetLinHash - Linear Hashing
285// =============================================================================
286
288{
289 cout << "\n";
290 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
291 cout << "║ EXAMPLE 2: DynSetLinHash (Linear Hashing) ║\n";
292 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
293
294 cout << "Linear hashing grows the table incrementally, one bucket at a time.\n";
295 cout << "This avoids expensive full-table rehashing operations.\n\n";
296
298
299 cout << "Inserting 100 random integers...\n\n";
300
301 mt19937 rng(42);
302 uniform_int_distribution<int> dist(1, 10000);
303
304 for (int i = 0; i < 100; ++i)
305 set.insert(dist(rng));
306
307 cout << "Set size: " << set.size() << "\n";
308
309 cout << "\n--- Membership testing ---\n\n";
310
311 // Reset RNG and check first few values
312 rng.seed(42);
313 for (int i = 0; i < 5; ++i) {
314 int v = dist(rng);
315 cout << " contains(" << v << "): "
316 << (set.contains(v) ? "YES" : "NO") << "\n";
317 }
318
319 cout << " contains(99999): "
320 << (set.contains(99999) ? "YES" : "NO") << "\n";
321}
322
323// =============================================================================
324// Example 3: ODhashTable - Open Addressing
325// =============================================================================
326
328{
329 cout << "\n";
330 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
331 cout << "║ EXAMPLE 3: ODhashTable (Open Addressing) ║\n";
332 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
333
334 cout << "ODhashTable stores all entries in a contiguous array.\n";
335 cout << "Collisions are resolved by double hashing + linear probing.\n\n";
336
337 // Create hash table with capacity 17 (prime for better distribution)
338 ODhashTable<int> table(17);
339
340 cout << "Table capacity: 17 (prime number recommended)\n\n";
341
342 // Insert values
343 vector<int> values = {10, 20, 30, 40, 50, 60, 70, 80};
344
345 cout << "Inserting values:\n";
346 for (int v : values) {
347 int* result = table.insert(v);
348 if (result)
349 cout << " ✓ Inserted: " << v << "\n";
350 else
351 cout << " ✗ Failed (duplicate?): " << v << "\n";
352 }
353
354 cout << "\nTable statistics:\n";
355 cout << " Size: " << table.size() << "\n";
356 cout << " Capacity: " << table.capacity() << "\n";
357 cout << " Load factor: " << fixed << setprecision(2)
358 << (double)table.size() / table.capacity() << "\n";
359
360 cout << "\n--- Search operations ---\n\n";
361
362 auto search_test = [&](int key) {
363 int* found = table.search(key);
364 cout << " search(" << key << "): "
365 << (found ? "FOUND" : "NOT FOUND") << "\n";
366 };
367
368 search_test(30);
369 search_test(50);
370 search_test(100);
371 search_test(70);
372
373 cout << "\n--- Remove operations ---\n\n";
374
375 cout << "Removing 40...\n";
376 table.remove(40);
377
378 search_test(40);
379
380 cout << "\nFinal size: " << table.size() << "\n";
381}
382
383// =============================================================================
384// Example 4: Performance Comparison
385// =============================================================================
386
388{
389 cout << "\n";
390 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
391 cout << "║ EXAMPLE 4: Performance Comparison ║\n";
392 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
393
394 const int N = 50000;
395 cout << "Benchmark: " << N << " insertions + " << N << " lookups\n\n";
396
397 mt19937 rng(12345);
398 vector<int> values;
399 for (int i = 0; i < N; ++i)
400 values.push_back(rng());
401
402 // DynSetLhash benchmark
403 {
405 auto start = chrono::high_resolution_clock::now();
406
407 for (int v : values)
408 set.insert(v);
409
410 auto mid = chrono::high_resolution_clock::now();
411
412 size_t found = 0;
413 for (int v : values)
414 if (set.contains(v))
415 ++found;
416
417 auto end = chrono::high_resolution_clock::now();
418
419 auto insert_ms = chrono::duration_cast<chrono::milliseconds>(mid - start).count();
420 auto search_ms = chrono::duration_cast<chrono::milliseconds>(end - mid).count();
421
422 cout << "DynSetLhash (chaining):\n";
423 cout << " Insert: " << insert_ms << " ms\n";
424 cout << " Search: " << search_ms << " ms (found " << found << ")\n";
425 cout << " Size: " << set.size() << "\n\n";
426 }
427
428 // DynSetLinHash benchmark
429 {
431 auto start = chrono::high_resolution_clock::now();
432
433 for (int v : values)
434 set.insert(v);
435
436 auto mid = chrono::high_resolution_clock::now();
437
438 size_t found = 0;
439 for (int v : values)
440 if (set.contains(v))
441 ++found;
442
443 auto end = chrono::high_resolution_clock::now();
444
445 auto insert_ms = chrono::duration_cast<chrono::milliseconds>(mid - start).count();
446 auto search_ms = chrono::duration_cast<chrono::milliseconds>(end - mid).count();
447
448 cout << "DynSetLinHash (linear hashing):\n";
449 cout << " Insert: " << insert_ms << " ms\n";
450 cout << " Search: " << search_ms << " ms (found " << found << ")\n";
451 cout << " Size: " << set.size() << "\n\n";
452 }
453
454 // ODhashTable benchmark
455 {
456 ODhashTable<int> table(N * 2);
457 auto start = chrono::high_resolution_clock::now();
458
459 for (int v : values)
460 (void) table.insert(v);
461
462 auto mid = chrono::high_resolution_clock::now();
463
464 size_t found = 0;
465 for (int v : values)
466 if (table.search(v))
467 ++found;
468
469 auto end = chrono::high_resolution_clock::now();
470
471 auto insert_ms = chrono::duration_cast<chrono::milliseconds>(mid - start).count();
472 auto search_ms = chrono::duration_cast<chrono::milliseconds>(end - mid).count();
473
474 cout << "ODhashTable (open addressing):\n";
475 cout << " Insert: " << insert_ms << " ms\n";
476 cout << " Search: " << search_ms << " ms (found " << found << ")\n";
477 cout << " Size: " << table.size() << "\n\n";
478 }
479}
480
481// =============================================================================
482// Main
483// =============================================================================
484
485int main(int argc, char* argv[])
486{
487 string selector;
488 for (int i = 1; i < argc; ++i)
489 {
490 const string arg = argv[i];
491 if (arg == "--help" || arg == "-h")
492 {
493 print_usage(argv[0]);
494 return 0;
495 }
496 if (arg == "-s")
497 {
498 if (i + 1 >= argc)
499 {
500 print_usage(argv[0]);
501 return 1;
502 }
503 selector = argv[++i];
504 continue;
505 }
506
507 cout << "Unknown argument: " << arg << "\n";
508 print_usage(argv[0]);
509 return 1;
510 }
511
512 if (selector.empty())
513 selector = "all";
514
515 cout << "\n";
516 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
517 cout << "║ Hash Tables in Aleph-w Library ║\n";
518 cout << "║ ║\n";
519 cout << "║ Aleph-w Library - https://github.com/lrleon/Aleph-w ║\n";
520 cout << "╚══════════════════════════════════════════════════════════════════╝\n";
521
522 const bool run_all = (selector == "all");
523 if (run_all || selector == "chaining")
525 if (run_all || selector == "linear")
527 if (run_all || selector == "open")
528 demo_odhash();
529 if (run_all || selector == "performance")
531
532 cout << "\n";
533 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
534 cout << "║ Hash Table Summary ║\n";
535 cout << "╠══════════════════════════════════════════════════════════════════╣\n";
536 cout << "║ DynSetLhash: Separate chaining, flexible, easy deletion ║\n";
537 cout << "║ DynSetLinHash: Linear hashing, smooth growth, no spikes ║\n";
538 cout << "║ ODhashTable: Open addressing, cache-friendly, fast ║\n";
539 cout << "║ ║\n";
540 cout << "║ Choose based on your use case: ║\n";
541 cout << "║ • DynSetLhash: General purpose, many deletions ║\n";
542 cout << "║ • DynSetLinHash: Realtime, predictable performance ║\n";
543 cout << "║ • ODhashTable: Known size, maximum speed ║\n";
544 cout << "╚══════════════════════════════════════════════════════════════════╝\n\n";
545
546 return 0;
547}
int main()
bool contains(const Key &key) const noexcept
Alias for has()
void remove(Key *key)
Removes a key from the hash table using its pointer.
Key * insert(const Key &key)
Inserts key into the hash set.
void empty() noexcept
empty the list
Definition htlist.H:1689
Open addressing hash table with double hashing collision resolution.
Definition tpl_odhash.H:180
Key * search(const Key &key) const noexcept
searches the table for the key.
Definition tpl_odhash.H:537
void remove(const Key &key)
Remove a key from the hash table.
Definition tpl_odhash.H:897
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:685
constexpr size_t size() const noexcept
Returns the number of entries in the table.
Definition hashDry.H:612
constexpr size_t capacity() const noexcept
Returns the current capacity of the table.
Definition hashDry.H:622
Key * insert(const Key &key)
Inserts a key into the hash table (copy version).
Definition hashDry.H:203
static mt19937 rng
#define N
Definition fib.C:294
void demo_performance()
void demo_dynset_linhash()
static void print_usage(const char *prog)
void demo_dynset_lhash()
void demo_odhash()
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Dynamic set implementations based on hash tables.
Open addressing hash table with double hashing.