Design HashMap in Python

A HashMap is a key-value data structure that provides fast lookups, insertions, and deletions. We can implement a custom HashMap in Python using an array of linked lists to handle collisions through chaining.

HashMap Operations

Our HashMap will support three main operations ?

  • put(key, value) − Insert or update a key-value pair
  • get(key) − Retrieve the value for a given key, return -1 if not found
  • remove(key) − Delete a key-value pair from the HashMap

Implementation Strategy

We'll use separate chaining to handle hash collisions. Each bucket in our hash table contains a linked list of key-value pairs.

Hash Table 0 1 2 ... key:2, val:1 key:5, val:10 NULL Hash Function: key % 1033 Example: hash(2) = 2 % 1033 = 2 ? bucket 2 Example: hash(5) = 5 % 1033 = 5 ? bucket 5

Node Class

First, we create a Node class to store key-value pairs in our linked lists ?

class Node:
    def __init__(self, key, val):
        self.key = key
        self.val = val
        self.next = None

LinkedList Class

Each bucket uses a linked list to handle collisions ?

class LinkedList:
    def __init__(self):
        self.prehead = Node(None, None)  # Dummy head node
    
    def search(self, key):
        p = self.prehead.next
        while p:
            if p.key == key:
                return p
            p = p.next
        return None
    
    def add(self, key, val):
        p = self.search(key)
        if p:
            p.val = val  # Update existing key
        else:
            node = Node(key, val)
            node.next = self.prehead.next
            self.prehead.next = node  # Insert at beginning
    
    def get(self, key):
        p = self.search(key)
        return p.val if p else None
    
    def remove(self, key):
        prev = self.prehead
        cur = prev.next
        while cur:
            if cur.key == key:
                prev.next = cur.next
                break
            prev, cur = cur, cur.next

MyHashMap Class

Now we implement the main HashMap class ?

class MyHashMap:
    def __init__(self):
        self.size = 1033  # Prime number for better distribution
        self.arr = [LinkedList() for _ in range(self.size)]
    
    def _hash(self, key):
        return key % self.size
    
    def put(self, key, value):
        h = self._hash(key)
        self.arr[h].add(key, value)
    
    def get(self, key):
        h = self._hash(key)
        ret = self.arr[h].get(key)
        return ret if ret is not None else -1
    
    def remove(self, key):
        h = self._hash(key)
        self.arr[h].remove(key)

# Test the HashMap implementation
hashmap = MyHashMap()
hashmap.put(1, 1)
hashmap.put(2, 2)
print(hashmap.get(1))  # Output: 1
print(hashmap.get(3))  # Output: -1 (not found)
hashmap.put(2, 1)      # Update value
print(hashmap.get(2))  # Output: 1
hashmap.remove(2)      # Remove key
print(hashmap.get(2))  # Output: -1 (removed)
1
-1
1
-1

How It Works

The HashMap uses separate chaining for collision resolution. When multiple keys hash to the same bucket, they are stored in a linked list at that position. The hash function key % 1033 distributes keys across 1033 buckets.

Time Complexity

Operation Average Case Worst Case
Put O(1) O(n)
Get O(1) O(n)
Remove O(1) O(n)

Conclusion

This HashMap implementation uses separate chaining with linked lists to handle collisions efficiently. The prime number 1033 for bucket size helps distribute keys evenly and minimize collisions.

Updated on: 2026-03-25T08:47:42+05:30

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements