Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_dynSetHash.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
45# ifndef TPL_DYNSETHASH_H
46# define TPL_DYNSETHASH_H
47
48# include <algorithm>
49# include <typeinfo>
50# include <ahDry.H>
51# include <ahIterator.H>
52# include <primes.H>
53# include <htlist.H>
54# include <tpl_dynArray.H>
55# include <tpl_dynMapOhash.H>
56# include <tpl_dynLhash.H>
57# include <tpl_linHash.H>
58# include <ah-concepts.H>
59
60
61namespace Aleph
62{
74 template <typename Key,
75 template <typename, class> class HashTable = LhashTable,
79 : public HashTable<Key, Cmp>,
80 public GenericTraverse<DynHashTable<Key, HashTable, Cmp>>,
81 public LocateFunctions<DynHashTable<Key, HashTable, Cmp>, Key>,
82 public FunctionalMethods<DynHashTable<Key, HashTable, Cmp>, Key>,
83 public GenericKeys<DynHashTable<Key, HashTable, Cmp>, Key>,
84 public EqualToMethod<DynHashTable<Key, HashTable, Cmp>>,
85 public StlAlephIterator<DynHashTable<Key, HashTable, Cmp>>
86 {
87 protected:
89
90 using Bucket = typename HashTable<Key, Cmp>::Bucket;
91
92 public:
94 using Hash_Fct = typename Base::Hash_Fct;
95
96 using Hash_Fct_Ptr = typename Base::Hash_Fct_Ptr;
97
98 using Key_Type = Key;
99
100 using Item_Type = Key;
101
115 Cmp cmp = Cmp(),
116 float lower_alpha = hash_default_lower_alpha,
117 float upper_alpha = hash_default_upper_alpha)
118 : Base(len, hash_fct, cmp, lower_alpha, upper_alpha, true, true)
119 {
120 // empty
121 }
122
123 DynHashTable(size_t len, Hash_Fct hash_fct, Cmp cmp,
124 float lower_alpha, float upper_alpha)
125 : Base(len, hash_fct, cmp, lower_alpha, upper_alpha, true, true)
126 {
127 // empty
128 }
129
130 private:
131 void copy(const DynHashTable & other)
132 {
133 for (typename Base::Iterator it(other); it.has_curr(); it.next_ne())
134 {
135 auto *bucket = static_cast<Bucket *>(it.get_curr());
136 insert(bucket->get_key());
137 }
138 }
139
140 public:
157 : Base(other.len, other.hash_fct,
158 const_cast<DynHashTable &>(other).get_compare(),
159 other.lower_alpha, other.upper_alpha, true, true)
160 {
161 copy(other);
162 }
163
165 : Base(other.len, other.hash_fct, other.get_compare(),
166 other.lower_alpha, other.upper_alpha, true, true)
167 {
168 this->swap(other);
169 }
170
172
174 {
175 this->empty();
176 }
177
183 void clear() { this->empty(); }
184
186
192 bool contains(const Key & key) const noexcept { return Base::contains(key); }
193
199 bool is_empty() const noexcept { return this->Base::is_empty(); }
200
202 {
203 if (this == &other)
204 return *this;
205
206 this->empty();
207 copy(other);
208
209 return *this;
210 }
211
213 {
214 if (this == &other)
215 return *this;
216
217 this->empty();
218 this->swap(other);
219 return *this;
220 }
221
222 protected:
223 Key * insert_bucket(Bucket *bucket)
224 {
225 auto *ret_val = static_cast<Bucket *>(this->Base::insert(bucket));
226 if (ret_val == nullptr) // is the key in the table?
227 { // yes! ==> free bucket
228 delete bucket;
229 return nullptr;
230 }
231
232 return &ret_val->get_key();
233 }
234
235 std::pair<Key *, bool> search_or_insert_bucket(Bucket *bucket)
236 {
237 auto *ret_val = static_cast<Bucket *>(this->Base::search_or_insert(bucket));
238 if (ret_val != bucket) // is the key in the table?
239 { // yes! ==> free bucket
240 delete bucket;
241 return {&ret_val->get_key(), true};
242 }
243
244 return {&ret_val->get_key(), false};
245 }
246
247 public:
250 Key * insert(const Key & key)
251 {
252 return insert_bucket(new Bucket(key));
253 }
254
255 Key * insert(Key && key)
256 {
257 return insert_bucket(new Bucket(std::forward<Key>(key)));
258 }
259
260 Key * search_or_insert(const Key & key)
261 {
262 return get<0>(search_or_insert_bucket(new Bucket(key)));
263 }
264
265 Key * search_or_insert(Key && key)
266 {
267 return get<0>(search_or_insert_bucket(new Bucket(std::forward<Key>(key))));
268 }
269
270 // Returns true if key is already in the table. Otherwise, inserts key and
271 // returns false.
272 std::pair<Key *, bool> contains_or_insert(const Key & key)
273 {
274 return search_or_insert_bucket(new Bucket(key));
275 }
276
277 std::pair<Key *, bool> contains_or_insert(Key && key)
278 {
279 return search_or_insert_bucket(new Bucket(std::forward<Key>(key)));
280 }
281
282 Key * add(const Key & key)
283 {
284 return insert_bucket(new Bucket(key));
285 }
286
287 Key * add(Key && key)
288 {
289 return insert_bucket(new Bucket(std::forward<Key>(key)));
290 }
291
292 Key * append(const Key & key)
293 {
294 return insert_bucket(new Bucket(key));
295 }
296
297 Key * append(Key && key)
298 {
299 return insert_bucket(new Bucket(std::forward<Key>(key)));
300 }
301
309 Key * search(const Key & key) const noexcept
310 {
311 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
312 return bucket != nullptr ? &bucket->get_key() : nullptr;
313 }
314
320 bool has(const Key & key) const noexcept
321 {
322 return this->Base::search(key) != nullptr;
323 }
324
325 const Key &find(const Key & key) const
326 {
327 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
328 ah_domain_error_if(bucket == nullptr) << "Key not found in hash";
329
330 return bucket->get_key();
331 }
332
333 Key &find(const Key & key)
334 {
335 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
336
337 ah_domain_error_if(bucket == nullptr) << "Key not found in hash";
338
339 return bucket->get_key();
340 }
341
342 protected:
343 static Bucket * key_to_bucket(Key *key)
344 {
345 return static_cast<Bucket *>(Dnode<Key>::data_to_node(*key));
346 }
347
348 public:
363 void remove(Key *key)
364 {
365 Bucket *bucket = key_to_bucket(key);
366 this->Base::remove(bucket);
367 delete bucket;
368 }
369
370 Key remove(const Key & key)
371 {
372 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
373 ah_domain_error_if(bucket == nullptr) << "Key not found in hash table";
374
375 this->Base::remove(bucket);
376 auto ret_val = bucket->get_key();
377 delete bucket;
378 return ret_val;
379 }
380
381 class Iterator : public Base::Iterator
382 {
383 public:
384 using Item_Type = Key;
385
387
390
392
394 {
395 return this->Base::Iterator::get_curr_ne()->get_key();
396 }
397
399 {
400 return const_cast<Iterator *>(this)->get_curr_ne();
401 }
402
403 const Key &get_curr() const
404 {
405 return const_cast<Iterator *>(this)->get_curr();
406 }
407
408 Key &get_curr()
409 {
410 return this->Base::Iterator::get_curr()->get_key();
411 }
412
413 void del() { delete this->Base::Iterator::del(); }
414 };
415
416 const Key &get_first() const
417 {
418 return this->get_it().get_curr();
419 }
420
422 {
423 return this->get_it().get_curr();
424 }
425
426 const Key &get_last() const
427 {
428 auto it = this->get_it();
429 it.reset_last();
430 return it.get_curr();
431 }
432
433 Key &get_last()
434 {
435 auto it = this->get_it();
436 it.reset_last();
437 return it.get_curr();
438 }
439 };
440
445 template <typename Key, class Cmp = Aleph::equal_to<Key>>
447 struct DynSetLhash : public DynHashTable<Key, LhashTable, Cmp>
448 {
450 using Base::Base;
451 };
452
457 template <typename Key, class Cmp = Aleph::equal_to<Key>>
459 struct DynSetLinHash : public DynHashTable<Key, LinearHashTable, Cmp>
460 {
462 using Base::Base;
463 };
464
469 template <typename Key, class Cmp = Aleph::equal_to<Key>>
471
476 template <typename Key, typename Data,
477 template <class, class> class HashTable = LhashTable,
481 : public DynHashTable<std::pair<Key, Data>,
482 HashTable, Dft_Pair_Cmp<Key, Data, Cmp>>
483 {
484 using Pair = std::pair<Key, Data>;
485
486 using Base =
488
489 using Bucket = typename Base::Bucket;
490
491 public:
492 using Hash_Fct = std::function<size_t(const Key &)>;
493 using Hash_Fct_Ptr = size_t (*)(const Key &);
494
495 private:
496 // Store the original hash function that works on Key (not Pair)
497 // This allows heterogeneous search without constructing Data()
499
500 static constexpr bool has_search_with_custom_hash =
501 requires(const DynMapHashTable *self, Hash_Fct_Ptr hf, const Key & k)
502 {
503 self->search_with_custom_hash(hf, k);
504 };
505
506 public:
507 static Data &get_data(const Key & key)
508 {
509 return key_to_pair<Key, Data>(&const_cast<Key &>(key))->second;
510 }
511
512 static const Key &get_key(Data *data_ptr)
513 {
514 return data_to_pair<Key, Data>(data_ptr)->first;
515 }
516
517 using Value_Type = Data;
518
519 // using Base::Base; // no more need. But I don't remember why I put it
520 using Base::insert; // in this way, insert with a pair is exported
521 using Iterator = typename Base::Iterator;
522
525 Cmp cmp = Cmp(),
526 float lower_alpha = hash_default_lower_alpha,
527 float upper_alpha = hash_default_upper_alpha)
528 : Base(len, std::bind(map_hash_fct<Key, Data, Hash_Fct>,
529 hash_fct, std::placeholders::_1),
530 Dft_Pair_Cmp<Key, Data, Cmp>(cmp), lower_alpha, upper_alpha),
531 original_hash_fct(hash_fct) {}
532
536 Pair * insert(const Key & key, const Data & data)
537 {
538 return this->insert_bucket(new typename Base::Bucket(Pair(key, data)));
539 }
540
541 Pair * insert(const Key & key, Data && data)
542 {
543 return this->insert_bucket
544 (new typename Base::Bucket(Pair(key, std::forward<Data>(data))));
545 }
546
547 Pair * insert(Key && key, Data && data)
548 {
549 return this->insert_bucket
550 (new typename Base::Bucket(Pair(std::forward<Key>(key), std::forward<Data>(data))));
551 }
552
553 Pair * insert(Key && key, const Data & data)
554 {
555 return this->insert_bucket
556 (new typename Base::Bucket(Pair(std::forward<Key>(key), data)));
557 }
558
565 Pair * search(const Key & key) const noexcept
566 {
567 if constexpr (has_search_with_custom_hash)
568 {
569 auto *bucket = static_cast<Bucket *>(
570 this->search_with_custom_hash(original_hash_fct, key));
571 return bucket != nullptr ? &bucket->get_key() : nullptr;
572 }
573 else
574 return Base::search(Pair(key, Data()));
575 }
576
577 Pair * search(Key && key) const noexcept
578 {
579 if constexpr (has_search_with_custom_hash)
580 {
581 auto *bucket = static_cast<Bucket *>(
582 this->search_with_custom_hash(original_hash_fct, key));
583 return bucket != nullptr ? &bucket->get_key() : nullptr;
584 }
585 else
586 return Base::search(Pair(std::forward<Key>(key), Data()));
587 }
588
590 bool has(const Key & key) const noexcept { return search(key) != nullptr; }
591
592 bool has(Key && key) const noexcept { return search(std::forward<Key>(key)) != nullptr; }
593
595
601 bool contains(const Key & key) const noexcept { return has(key); }
602
609 bool contains(Key && key) const noexcept { return has(std::forward<Key>(key)); }
610
619 Data &find(const Key & key)
620 {
621 auto *pair = search(key);
622 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
623 return pair->second;
624 }
625
626 const Data &find(const Key & key) const
627 {
628 auto *pair = search(key);
629 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
630 return pair->second;
631 }
632
639 Data &operator [](const Key & key)
640 {
641 return this->search_or_insert(Pair(key, Data()))->second;
642 }
643
644 const Data &operator [](const Key & key) const
645 {
646 return this->find(key);
647 }
648
649 Data &operator [](Key && key)
650 {
651 return this->search_or_insert(Pair(std::forward<Key>(key), Data()))->second;
652 }
653
654 const Data &operator [](Key && key) const
655 {
656 return this->find(std::forward<Key>(key));
657 }
658
661 void remove_by_data(Data & data)
662 {
664 }
665
678 Data remove(const Key & key)
679 {
680 auto *pair = search(key);
681 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
682
683 auto ret_val = std::move(pair->second);
684 auto *bucket = Base::key_to_bucket(pair);
685 this->Base::Base::remove(bucket);
686 delete bucket;
687 return ret_val;
688 }
689
690 Data remove(Key && key)
691 {
692 return remove(key); // Forward to const& version
693 }
694
696 {
697 return this->template maps<Key>([](auto p) { return p.first; });
698 }
699
701 {
702 return this->template maps<Data>([](auto p) { return p.second; });
703 }
704
706 {
708 for (Iterator it(*this); it.has_curr(); it.next_ne())
709 ret.append(&it.get_curr().second);
710 return ret;
711 }
712
714 {
716 for (Iterator it(*this); it.has_curr(); it.next_ne())
717 ret.append(&it.get_curr());
718 return ret;
719 }
720 };
721
726 template <typename Key, typename Data,
729
734 template <typename Key, typename Data,
737
738
739 // Implementation coming from ahFunctional.H
740
741 template <typename T, template <typename> class Container>
742 inline
744 {
745 DynSetLhash<T> table(c1);
746 c2.for_each([&table](const T & item)
747 {
748 table.insert(item);
749 });
750 return table.keys();
751 }
752
753 template <typename T, template <typename> class Container = DynList>
754 inline
756 {
759 return set1.filter([&set2](const T & i) { return set2.contains(i); });
760 }
761
762 template <typename T, template <typename> class Container>
763 inline
765 {
766 return DynSetLhash<T>(c).keys();
767 }
768
769 template <typename T, template <typename> class Container>
770 inline
772 {
774 DynSetLhash<T> table;
775
776 c.for_each([&table, &ret](const T & i)
777 {
778 auto *ptr = table.insert(i);
779 if (ptr == nullptr)
780 ret.append(i);
781 });
782
783 return ret;
784 }
785
786 template <typename T, template <typename> class Container>
787 inline
789 {
791 DynSetLhash<T> table;
792
793 size_t i = 0;
794 c.for_each([&table, &ret, &i](const T & item)
795 {
796 auto *ptr = table.insert(item);
797 if (ptr == nullptr)
798 ret.append(std::pair<T, size_t>(item, i));
799 ++i;
800 });
801
802 return ret;
803 }
804} // end namespace Aleph
805
806# endif // TPL_DYNSETHASH_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
DRY (Don't Repeat Yourself) utilities and macros.
#define Special_Ctors(Set_Type, Type)
Generates special constructors for containers.
Definition ahDry.H:113
Iterator traits and STL-compatible iterator wrappers.
static Dnode * data_to_node(T &data) noexcept
Given an reference to the data in the node, returns a pointer to the Dnode object that contains it.
Definition tpl_dnode.H:248
const Key & get_curr_ne() const noexcept
Iterator() noexcept=default
Default constructor creates an "end" iterator.
Self-adjusting dynamic hash table.
Key * add(const Key &key)
Key * search_or_insert(const Key &key)
Key * search(const Key &key) const noexcept
Searches for a key in the hash table.
Key * insert_bucket(Bucket *bucket)
Key * append(const Key &key)
std::pair< Key *, bool > search_or_insert_bucket(Bucket *bucket)
bool contains(const Key &key) const noexcept
Return true if the key exists in the table.
typename HashTable< Key, Cmp >::Bucket Bucket
DynHashTable(size_t len=Primes::DefaultPrime, Hash_Fct_Ptr hash_fct=Aleph::dft_hash_ptr_fct< Key >, Cmp cmp=Cmp(), float lower_alpha=hash_default_lower_alpha, float upper_alpha=hash_default_upper_alpha)
Creates a dynamic linear hash table.
DynHashTable(DynHashTable &&other) noexcept
void copy(const DynHashTable &other)
DynHashTable(const DynHashTable &other)
Copy constructor.
HashTable< Key, Cmp > Base
void remove(Key *key)
Removes a key from the hash table using its pointer.
const Key & get_last() const
DynHashTable & operator=(const DynHashTable &other)
Key * insert(const Key &key)
Inserts key into the hash set.
static Bucket * key_to_bucket(Key *key)
std::pair< Key *, bool > contains_or_insert(Key &&key)
Key * insert(Key &&key)
const Key & find(const Key &key) const
Key remove(const Key &key)
typename Base::Hash_Fct Hash_Fct
Hash function type.
DynHashTable(size_t len, Hash_Fct hash_fct, Cmp cmp, float lower_alpha, float upper_alpha)
void clear()
Empties the container.
typename Base::Hash_Fct_Ptr Hash_Fct_Ptr
Key * add(Key &&key)
std::pair< Key *, bool > contains_or_insert(const Key &key)
bool has(const Key &key) const noexcept
Checks if a key exists in the hash table.
bool is_empty() const noexcept
Checks if the container is empty.
Key * append(Key &&key)
const Key & get_first() const
Key & find(const Key &key)
Key * search_or_insert(Key &&key)
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
bool has(Key &&key) const noexcept
Data & operator[](const Key &key)
Subscript operator for map access/insertion.
void remove_by_data(Data &data)
Removes from the table the key whose pointer must be the result of a prior insertion or search.
Hash_Fct_Ptr original_hash_fct
size_t(*)(const Key &) Hash_Fct_Ptr
Pair * insert(Key &&key, Data &&data)
static const Key & get_key(Data *data_ptr)
DynList< Data * > values_ptr()
DynList< Key > values() const
bool has(const Key &key) const noexcept
Checks if a key exists in the map.
const Data & find(const Key &key) const
Pair * insert(Key &&key, const Data &data)
std::pair< Key, Data > Pair
Pair * insert(const Key &key, const Data &data)
Inserts into the hash map the pair (key, record) indexed by key.
Data remove(const Key &key)
Removes a key-value pair from the map and returns the value.
bool contains(Key &&key) const noexcept
Checks if a key exists in the map (move version).
typename Base::Bucket Bucket
Pair * search(Key &&key) const noexcept
typename Base::Iterator Iterator
bool contains(const Key &key) const noexcept
Alias for has()
DynList< Pair * > items_ptr()
Pair * search(const Key &key) const noexcept
Searches for key and, if found, returns a pointer to the associated pair stored in the table.
std::function< size_t(const Key &)> Hash_Fct
DynList< Key > keys() const
Data & find(const Key &key)
Finds and returns a reference to the value associated with key.
static Data & get_data(const Key &key)
static constexpr bool has_search_with_custom_hash
DynMapHashTable(size_t len=Primes::DefaultPrime, Hash_Fct_Ptr hash_fct=dft_hash_ptr_fct< Key >, Cmp cmp=Cmp(), float lower_alpha=hash_default_lower_alpha, float upper_alpha=hash_default_upper_alpha)
Pair * insert(const Key &key, Data &&data)
Equality test for containers.
Definition ah-dry.H:1959
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:658
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criterion.
Definition ah-dry.H:1437
Common sequential searching methods on containers.
Definition ah-dry.H:200
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
Equivalence relation constraint for equality comparators.
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4129
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t map_hash_fct(Fct fct, const std::pair< Key, Data > &p) noexcept
Definition hash-fct.H:1137
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
DynList< T > intercept(const Container< T > &c1, const Container< T > &c2)
Return intersection of two containers as a DynList.
DynList< std::pair< T, size_t > > repeated_with_index(const Container< T > &c)
Return repeated elements paired with their occurrence count.
DynList< T > repeated(const Container< T > &c)
Return elements that appear more than once in the container.
const float hash_default_upper_alpha
Definition hash-dry.C:40
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Definition ahPair.H:89
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
const float hash_default_lower_alpha
Definition hash-dry.C:38
const unsigned long DefaultPrime
Default prime number used when no specific size is requested.
Definition primes.C:381
STL namespace.
Prime number utilities for hash tables and mathematical operations.
Default comparator for pair types in hash maps.
Definition ahDry.H:190
Hash-based dynamic set (defined in tpl_dynSetHash.H).
DynHashTable< Key, LhashTable, Cmp > Base
DynHashTable< Key, LinearHashTable, Cmp > Base
Generic hash table with collision resolution by separate chaining and buckets without virtual destruc...
Definition tpl_lhash.H:838
Generic list of items stored in a container.
Definition ah-dry.H:1846
Aleph::DynList< T > keys() const
Definition ah-dry.H:1863
Generic traversal of the container through its iterator.
Definition ah-dry.H:71
static int * k
Lazy and scalable dynamic array implementation.
Dynamic hash table mapping keys to records with separate chaining.
Dynamic map with open hashing.
Linear hashing with chaining.