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 Bucket *ret_val = 0;
346 const auto offset = reinterpret_cast<size_t>(&ret_val->get_key());
347
348 return reinterpret_cast<Bucket *>(reinterpret_cast<size_t>(key) - offset);
349 }
350
351 public:
366 void remove(Key *key)
367 {
368 Bucket *bucket = key_to_bucket(key);
369 this->Base::remove(bucket);
370 delete bucket;
371 }
372
373 Key remove(const Key & key)
374 {
375 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
376 ah_domain_error_if(bucket == nullptr) << "Key not found in hash table";
377
378 this->Base::remove(bucket);
379 auto ret_val = bucket->get_key();
380 delete bucket;
381 return ret_val;
382 }
383
384 class Iterator : public Base::Iterator
385 {
386 public:
387 using Item_Type = Key;
388
390
393
395
397 {
398 return this->Base::Iterator::get_curr_ne()->get_key();
399 }
400
402 {
403 return const_cast<Iterator *>(this)->get_curr_ne();
404 }
405
406 const Key &get_curr() const
407 {
408 return const_cast<Iterator *>(this)->get_curr();
409 }
410
411 Key &get_curr()
412 {
413 return this->Base::Iterator::get_curr()->get_key();
414 }
415
416 void del() { delete this->Base::Iterator::del(); }
417 };
418
419 const Key &get_first() const
420 {
421 return this->get_it().get_curr();
422 }
423
425 {
426 return this->get_it().get_curr();
427 }
428
429 const Key &get_last() const
430 {
431 auto it = this->get_it();
432 it.reset_last();
433 return it.get_curr();
434 }
435
436 Key &get_last()
437 {
438 auto it = this->get_it();
439 it.reset_last();
440 return it.get_curr();
441 }
442 };
443
448 template <typename Key, class Cmp = Aleph::equal_to<Key>>
450 struct DynSetLhash : public DynHashTable<Key, LhashTable, Cmp>
451 {
453 using Base::Base;
454 };
455
460 template <typename Key, class Cmp = Aleph::equal_to<Key>>
462 struct DynSetLinHash : public DynHashTable<Key, LinearHashTable, Cmp>
463 {
465 using Base::Base;
466 };
467
472 template <typename Key, class Cmp = Aleph::equal_to<Key>>
474
479 template <typename Key, typename Data,
480 template <class, class> class HashTable = LhashTable,
484 : public DynHashTable<std::pair<Key, Data>,
485 HashTable, Dft_Pair_Cmp<Key, Data, Cmp>>
486 {
487 using Pair = std::pair<Key, Data>;
488
489 using Base =
491
492 using Bucket = typename Base::Bucket;
493
494 public:
495 using Hash_Fct = std::function<size_t(const Key &)>;
496 using Hash_Fct_Ptr = size_t (*)(const Key &);
497
498 private:
499 // Store the original hash function that works on Key (not Pair)
500 // This allows heterogeneous search without constructing Data()
502
503 static constexpr bool has_search_with_custom_hash =
504 requires(const DynMapHashTable *self, Hash_Fct_Ptr hf, const Key & k)
505 {
506 self->search_with_custom_hash(hf, k);
507 };
508
509 public:
510 static Data &get_data(const Key & key)
511 {
512 return key_to_pair<Key, Data>(&const_cast<Key &>(key))->second;
513 }
514
515 static const Key &get_key(Data *data_ptr)
516 {
517 return data_to_pair<Key, Data>(data_ptr)->first;
518 }
519
520 using Value_Type = Data;
521
522 // using Base::Base; // no more need. But I don't remember why I put it
523 using Base::insert; // in this way, insert with a pair is exported
524 using Iterator = typename Base::Iterator;
525
528 Cmp cmp = Cmp(),
529 float lower_alpha = hash_default_lower_alpha,
530 float upper_alpha = hash_default_upper_alpha)
531 : Base(len, std::bind(map_hash_fct<Key, Data, Hash_Fct>,
532 hash_fct, std::placeholders::_1),
533 Dft_Pair_Cmp<Key, Data, Cmp>(cmp), lower_alpha, upper_alpha),
534 original_hash_fct(hash_fct) {}
535
539 Pair * insert(const Key & key, const Data & data)
540 {
541 return this->insert_bucket(new typename Base::Bucket(Pair(key, data)));
542 }
543
544 Pair * insert(const Key & key, Data && data)
545 {
546 return this->insert_bucket
547 (new typename Base::Bucket(Pair(key, std::forward<Data>(data))));
548 }
549
550 Pair * insert(Key && key, Data && data)
551 {
552 return this->insert_bucket
553 (new typename Base::Bucket(Pair(std::forward<Key>(key), std::forward<Data>(data))));
554 }
555
556 Pair * insert(Key && key, const Data & data)
557 {
558 return this->insert_bucket
559 (new typename Base::Bucket(Pair(std::forward<Key>(key), data)));
560 }
561
568 Pair * search(const Key & key) const noexcept
569 {
570 if constexpr (has_search_with_custom_hash)
571 {
572 auto *bucket = static_cast<Bucket *>(
573 this->search_with_custom_hash(original_hash_fct, key));
574 return bucket != nullptr ? &bucket->get_key() : nullptr;
575 }
576 else
577 return Base::search(Pair(key, Data()));
578 }
579
580 Pair * search(Key && key) const noexcept
581 {
582 if constexpr (has_search_with_custom_hash)
583 {
584 auto *bucket = static_cast<Bucket *>(
585 this->search_with_custom_hash(original_hash_fct, key));
586 return bucket != nullptr ? &bucket->get_key() : nullptr;
587 }
588 else
589 return Base::search(Pair(std::forward<Key>(key), Data()));
590 }
591
593 bool has(const Key & key) const noexcept { return search(key) != nullptr; }
594
595 bool has(Key && key) const noexcept { return search(std::forward<Key>(key)) != nullptr; }
596
598
604 bool contains(const Key & key) const noexcept { return has(key); }
605
612 bool contains(Key && key) const noexcept { return has(std::forward<Key>(key)); }
613
622 Data &find(const Key & key)
623 {
624 auto *pair = search(key);
625 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
626 return pair->second;
627 }
628
629 const Data &find(const Key & key) const
630 {
631 auto *pair = search(key);
632 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
633 return pair->second;
634 }
635
642 Data &operator [](const Key & key)
643 {
644 return this->search_or_insert(Pair(key, Data()))->second;
645 }
646
647 const Data &operator [](const Key & key) const
648 {
649 return this->find(key);
650 }
651
652 Data &operator [](Key && key)
653 {
654 return this->search_or_insert(Pair(std::forward<Key>(key), Data()))->second;
655 }
656
657 const Data &operator [](Key && key) const
658 {
659 return this->find(std::forward<Key>(key));
660 }
661
664 void remove_by_data(Data & data)
665 {
667 }
668
681 Data remove(const Key & key)
682 {
683 auto *pair = search(key);
684 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
685
686 auto ret_val = std::move(pair->second);
687 auto *bucket = Base::key_to_bucket(pair);
688 this->Base::Base::remove(bucket);
689 delete bucket;
690 return ret_val;
691 }
692
693 Data remove(Key && key)
694 {
695 return remove(key); // Forward to const& version
696 }
697
699 {
700 return this->template maps<Key>([](auto p) { return p.first; });
701 }
702
704 {
705 return this->template maps<Data>([](auto p) { return p.second; });
706 }
707
709 {
711 for (Iterator it(*this); it.has_curr(); it.next_ne())
712 ret.append(&it.get_curr().second);
713 return ret;
714 }
715
717 {
719 for (Iterator it(*this); it.has_curr(); it.next_ne())
720 ret.append(&it.get_curr());
721 return ret;
722 }
723 };
724
729 template <typename Key, typename Data,
732
737 template <typename Key, typename Data,
740
741
742 // Implementation coming from ahFunctional.H
743
744 template <typename T, template <typename> class Container>
745 inline
747 {
748 DynSetLhash<T> table(c1);
749 c2.for_each([&table](const T & item)
750 {
751 table.insert(item);
752 });
753 return table.keys();
754 }
755
756 template <typename T, template <typename> class Container = DynList>
757 inline
759 {
762 return set1.filter([&set2](const T & i) { return set2.contains(i); });
763 }
764
765 template <typename T, template <typename> class Container>
766 inline
768 {
769 return DynSetLhash<T>(c).keys();
770 }
771
772 template <typename T, template <typename> class Container>
773 inline
775 {
777 DynSetLhash<T> table;
778
779 c.for_each([&table, &ret](const T & i)
780 {
781 auto *ptr = table.insert(i);
782 if (ptr == nullptr)
783 ret.append(i);
784 });
785
786 return ret;
787 }
788
789 template <typename T, template <typename> class Container>
790 inline
792 {
794 DynSetLhash<T> table;
795
796 size_t i = 0;
797 c.for_each([&table, &ret, &i](const T & item)
798 {
799 auto *ptr = table.insert(item);
800 if (ptr == nullptr)
801 ret.append(std::pair<T, size_t>(item, i));
802 ++i;
803 });
804
805 return ret;
806 }
807} // end namespace Aleph
808
809# endif // TPL_DYNSETHASH_H
C++20 concepts for constraining comparison functors.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
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.
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)
Dynamic singly linked list with functional programming support.
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:1826
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:642
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criterion.
Definition ah-dry.H:1319
Common sequential searching methods on containers.
Definition ah-dry.H:196
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
Equivalence relation constraint for equality comparators.
Definition ah-concepts.H:97
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
Singly linked list implementations with head-tail access.
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
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:1110
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)
DynList< std::pair< T, size_t > > repeated_with_index(const Container< T > &c)
DynList< T > repeated(const Container< T > &c)
const float hash_default_upper_alpha
Definition hash-dry.C:40
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.
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
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:1714
Aleph::DynList< T > keys() const
Definition ah-dry.H:1729
Generic traversal of the container through its iterator.
Definition ah-dry.H:67
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.