This repository contains two complete hash map implementations written from scratch in Python, each using a different collision resolution strategy:
- Open Addressing with Quadratic Probing
- Separate Chaining with Linked Lists
Both implementations avoid Python’s built-in dict and instead rely on custom data structures to demonstrate a deep understanding of hashing mechanics, collision handling, resizing, and performance trade-offs.
.
├── hash_map_quadratic_sc.py
├── hash_map_separate_oa.py
├── a6_include.py
└── README.md
- Hash functions and key distribution
- Collision resolution strategies
- Load factor management
- Dynamic resizing and rehashing
- Trade-offs between time, space, and complexity
- Iterator support and full CRUD operations
File: hash_map_oa.py
This implementation uses open addressing, meaning all key/value pairs are stored directly inside the hash table array.
Quadratic probing is used when collisions occur:
(hash(key) + j²) % capacity
Probing continues until an empty slot or the target key is found.
- Uses tombstones to mark deleted entries.
- Tombstones preserve probe chains and are reused during insertion.
- Tombstones are ignored during resizing.
- Table resizes when load factor ≥ 0.5.
- Capacity is always adjusted to the next prime number.
- All active entries are rehashed into the new table.
- Lower memory overhead (no secondary structures).
- Cache-friendly due to contiguous storage.
- Performance degrades at higher load factors.
- Deletion logic is more complex due to tombstones.
putgetremovecontains_keyresize_tableclear- Iteration over active entries
File: hash_map_separate_chaining.py
This implementation uses separate chaining, where each index in the hash table contains a linked list of key/value pairs.
- Colliding keys are stored in the same bucket.
- Each bucket is implemented as a
LinkedList.
- Table resizes when load factor ≥ 1.0.
- Capacity is always adjusted to the next prime number.
- All key/value pairs are rehashed into the new table.
- Handles high load factors gracefully.
- Simpler deletion logic (remove from linked list).
- Slightly higher memory usage due to linked structures.
- Less cache-friendly than open addressing.
putgetremovecontains_keyresize_tableclearget_keys_and_values
The separate chaining implementation includes a find_mode function that:
- Counts string frequencies using the hash map.
- Returns all values with the highest frequency.
- Demonstrates real-world use of hashing for frequency analysis.
- Python 3
- Custom implementations of:
- Dynamic arrays
- Linked lists
- No external libraries
- No use of Python’s built-in
dict
Clone the repository:
git clone https://github.com/your-username/your-repo-name.git
cd your-repo-nameRun either implementation:
python hash_map_oa.py
python hash_map_sc.pyEach file includes a comprehensive test suite demonstrating correctness and edge cases.
This project was built to:
- Explore and compare two fundamental hash table designs.
- Reinforce understanding of collision resolution strategies.
- Demonstrate data-structure fundamentals commonly tested in interviews.
- Serve as a clear, well-documented portfolio example.