Design HashMap

Design a HashMap without using any built-in hash table libraries. To be specific, your design should include these functions:

  • put(key, value): Insert a (key,value) pair into the HashMap. If the value already exists in the HashMap, update the value.
  • get(key): Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key.
  • remove(key) : Remove the mapping for the value key if this map contains the mapping for the key.

Example:

MyHashMap hashMap = new MyHashMap();
hashMap.put(1, 1);          
hashMap.put(2, 2);         
hashMap.get(1);         // returns 1
hashMap.get(3);         // returns -1 (not found)
hashMap.put(2, 1);      // update the existing value
hashMap.get(2);         // returns 1 
hashMap.remove(2);      // remove the mapping for 2
hashMap.get(2);         // returns -1 (not found) 

Note:

  • All keys and values will be in the range of [0, 1000000].
  • The number of operations will be in the range of [1, 10000].
  • Please do not use the built-in HashMap library.

Solution : Traditional HashMap Implementation – Using an Array of LinkedList

1. The general implementation of HashMap uses bucket which is basically a chain of linked lists and each node containing <key,value> pair.

2. So if we have duplicate nodes, that doesn’t matter – it will still replicate each key with its value in the linked list node.

3. When we insert the pair (10,20) and then (10,30), there is technically no collision involved. We are just replacing the old value with the new value for a given key 10, since in both cases, 10 is equal to 10 and also the hash code for 10 is always 10.

4. The collision happens when multiple keys hash to the same bucket. In that case, we need to make sure that we can distinguish between those keys. Chaining collision resolution is one of those techniques which is used for this.

5. Just for the information. In JDK 8, HashMap has been tweaked so that if keys can be compared for ordering, then any densely-populated bucket is implemented as a tree, so that even if there are lots of entries with the same hash-code, the complexity is O(log n).

The HashMap Implementation

Time complexity : O(1) average and O(n) worst case – for all get(),put() and remove() methods.
Space complexity : O(n) – where n is the number of entries in HashMap.

class ListNode{
    int key;
    int value;
    ListNode next;
    
    public ListNode(int k, int v){
        this.key = k;
        this.value = v;
    }
}

class MyHashMap {

    private ListNode[] data = null;
    
    /** Initialize your data structure here. */
    public MyHashMap() {
        data = new ListNode[10000];
    }
    
    /** value will always be non-negative. */
    public void put(int key, int value) {
        int bucketNo = hash(key);
        ListNode head = data[bucketNo];
        ListNode node = new ListNode(key, value);
        if(head == null){
            data[bucketNo] = node;
            return;
        }
        if(head.key == key){
            head.value = value;
            return;
        }
        ListNode prev = head;
        ListNode current = head.next;
        while(current != null){
            if(current.key == key){
                current.value = value;
                return;
            }
            current = current.next;
            prev = prev.next;
        }
        prev.next = node;
        return;
    }
    
    /** Returns the value to which the specified key is mapped, 
     or -1 if this map contains no mapping for the key */
    public int get(int key) {
        int bucketNo = hash(key);
        ListNode head = data[bucketNo];
        ListNode current = head;
        int result = -1;
        while(current != null){
            if(current.key == key){
                result = current.value;
                break;
            }
            current = current.next;
        }
        return result;
    }
    
    /** Removes the mapping of the specified value key 
     if this map contains a mapping for the key */
    public void remove(int key) {
        int bucketNo = hash(key);
        ListNode head = data[bucketNo];
        if(head == null){
            return;
        }
        if(head.key == key){
            data[bucketNo] = head.next;
        }
        ListNode prev = head;
        ListNode current = head.next;
        while(current != null && current.next != null){
            if(current.key == key){
                prev.next = current.next;
                return;
            }
            prev = prev.next;
            current = current.next;
        }
        // when we are removing the last node of the LinkedList
        if(current != null && current.key == key){
            prev.next = null;
        }
        return;
    }
    
    private int hash(int key){
        return (key % data.length);
    }
}

/**
 * Your MyHashMap object will be instantiated and called as such:
 * MyHashMap obj = new MyHashMap();
 * obj.put(key,value);
 * int param_2 = obj.get(key);
 * obj.remove(key);
 */

Categories: Map

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s