Direct Access Table
Take huge array and use phone numbers as index in the array. if phone
number is not present entry is empty, else the array entry stores
pointer to records corresponding to phone number.
Searching in DA: O(1) but HUGE Extra Space required.
Hash Table is improvement over DAT
What is Hash Table
Search Complexity: Average=O(1), Worst case=O(n)
Disadvantages:
1. Elements are not sorted
2. Rehashing: Once all HT entries are filled it needs
resized/rehashing which is a time-consuming operation. Let HT size =
100, we want to insert 101st element. Not only the size of hash table is
enlarged to 150, all element in hash table have to be rehashed. This
insertion operation takes O(n).
Hash Function? Hash function maps a big number or string to a
small integer that can be used as index in hash table.
key -> |Hash Function| -> index of array/table
Internal Implementation of Hash Table
Let use consider simple example to insert following key,value pairs:
{"a",1}, {"b",2}, {"b",3}
Keys("a", "b", "b") are passed to hashfunction and indexes are returned
in bucket which acts as hash table
Collision: if same index is returned, chaining is done, ie
element is inserted into next position in vector
Hash table
|
How hashFunction() works
|
|
Hash Collision
This means hash function provides same index for 2 different keys.
1. Open Addressing
| Type of Open Addressing | What | Example |
|---|---|---|
| 1. Linear Probing |
if the target slot is occupied, the table checks the next
sequential slot (index + 1, wrapping around if necessary) until an empty slot is found. |
|
| 2. Quadratic Probing |
Uses a quadratic function to find the next slot. ax2 + bx + c |
|
| 3. Double Hashing | Uses double hash function to re-calculate the hash if collision occurs. In case of collision: hash1(x) = (hash1(x) + i*hash2(x))%hash_table_size |
2. Seperate Chaining
Each index of the hash table points to a secondary data structure,
typically a linked list. When a collision occurs, the new key is simply
appended to the list at that index
Insert(x): O(1). Insert at head of LL, Search(x): O(n). Need to search
complete list
hash(a) = 1, hash(b) = 1, hash(c) = 1
hash(d) = 1, hash(e) = 1
Hash Table (Array of Buckets)
+---------+
| Index 0 | ---> NULL
+---------+
| Index 1 | ---> [ "a" ] ---> [ "b" ] ---> [ "c" ] ---> NULL
+---------+
| Index 2 | ---> NULL
+---------+
| Index 3 | ---> [ "d" ] ---> [ "e" ] ---> NULL
+---------+
| Index 4 | ---> NULL
+---------+
C++ hashmap(unordered_map / unordered_set) = Seperate Chaining
A hash table container like std::unordered_map or std::unordered_set is
implemented using separate chaining for collision resolution.
Allocations: Similar to vector
A default-constructed hash table (:unordered_map <int,
string> map;) starts with a bucket count of 0.
1st map.insert(), it allocates its initial bucket array
(size=1).
Check Rehashing
Rehashing
load factor = number of elements / number of buckets
default max_load_factor() = 1.0
-
When an insertion causes the load factor to exceed 1.0 (i.e., elements
>= buckets), a rehash is triggered automatically.
During a rehash, a new, larger bucket array is allocated (typically scaling to the next prime number), and all existing elements are re-hashed and redistributed into the new buckets.
Let us consider unordered_map<int,string> storing unique keys. At start of program sizeof hash table=3
Key | Value
----------
01 | amit
02 | never
03 | give
Now, (4, up) need to be stored, but hash table has no space so size of
hash table is increased to 6. (old Hash function = %3) we can only goto
index number=2. But we want to reach 5. Hence Hash function is changed (new Hash function = %6). So hash is again calculated for existing values.
Implementations
2-left hashing
-
2 equal sized hash tables having 2 seperate hash functions are used.
Seperate chanining is used in both. Table1(hash1), Table2(hash2).
Cuckoo Hashing is a type of 2-left hashing
Inserting key into table: Always keep Table1 loaded, key is inserted into Table2 only when too many collisions happen on Table1.
Advantages? 1. On parallel systems. 2 cores can query 2 hash tables, ie Thread-1 can query Table1 and Thread2 Table2.
d-left Hashing
-
Split 1 hash table into d blocks. Similar to 2-left hashing, left most
hashtable should be loaded.
d buckets, n entries. Each bucket has n/d entries
Code
-
1. Student Hash table
Hash table stores Student data (Key:Value)
(1,20) (2,70) (42,80) (4,25) (12,44) (13,78) (14,32) (17,11) (37,97)
2. Leetcode Solved. Design a HashMap without using any built-in hash
table libraries.