Design your own Hash Map in Java
In this tutorial, we’ll learn how to design our own HashMap data structure in Java.
Overview
- A hash map is a data structure that stores key-value pairs.
- It insert and search the pair in constant time O(1) in best case.
- It is backed by an array, also known as hash table. Each index of an array is know as hash bucket.
- The key is sent to a hash function that performs arithmetic operations on it and returns the index of the key-value pair in the hash table.
- If hash function of two keys return the same index, it cause hash collision. In this case new pair is linked to the already store pair in that index and form a linked list
- If a bucket is having more than one key-value pairs linked by a linked list then equals function is used to find the correct key-value pair.
Implementation
Entry<K, V>
class to hold key-value pair. It is a generic class which is having key of type K, and value of type V. It also holds the address of next Entry in case of hash collisionMyHashMap<K, V>
hashash
method to find the index of the bucket for the key-value pair.MyHashMap<K, V>
hasput
andget
methods to insert and find the key-value pairs respectively.
package com.example.datastructure;
public class MyHashMap<K, V> {
private static int DEFAULT_CAPACITY = 16;
private Entry<K, V>[] table;
private int capacity;
MyHashMap() {
this(DEFAULT_CAPACITY);
}
MyHashMap(int capacity) {
this.capacity = capacity;
/**
* Initialize "Hash Table" with initial capacity which is nothing but an Array
* Each index of an array is called "Hash Bucket"
*/
this.table = new Entry[capacity];
}
/**
* Each Entry stores a key-value pair Each Entry also stores the address of next
* Entry in case of "Hash Collision"
*/
static class Entry<K, V> {
K key;
V value;
Entry<K, V> next;
Entry(K key, V value) {
this.key = key;
this.value = value;
}
Entry(K key, V value, Entry<K, V> next) {
this.key = key;
this.value = value;
this.next = next;
}
}
public void put(K key, V value) {
if (key == null) {
return;
}
// Create a key-value pair
Entry<K, V> newEntry = new Entry<>(key, value);
// Find the right Bucket by hashing the key
int hash = hash(key);
// if - Empty Bucket
if (table[hash] == null) {
table[hash] = newEntry;
// else - "Hash Bucket" is not Empty, Known as "Hash Collision"
// New Entry is created and linked to Previous Node in Same Bucket
} else {
Entry<K, V> current = table[hash];
Entry<K, V> previous = null;
while (current != null) {
if (current.key.equals(key)) {
current.value = newEntry.value;
return;
}
previous = current;
current = current.next;
}
previous.next = newEntry;
}
}
public V get(K key) {
if (key == null) {
return null;
}
// Find the right Bucket by hashing the key
int hash = hash(key);
// if - "Hash Bucket" is Empty, Return null
if (table[hash] == null) {
return null;
// else - "Hash Bucket" is not Empty
// Traverse through all the linked Nodes in the Bucket
// Use `equals` method to find the correct key-value pair
} else {
Entry<K, V> current = table[hash];
while (current != null) {
if (current.key.equals(key)) {
return current.value;
}
current = current.next;
}
}
return null;
}
private int hash(K key) {
// Using modulo "% capacity" to make sure that returned hash in the range of
// underlying Array size
return Math.abs(key.hashCode()) % capacity;
}
public static void main(String[] args) {
MyHashMap<String, Integer> likesPerPost = new MyHashMap<String, Integer>();
likesPerPost.put("Learning Hash Map", 5);
System.out.println(likesPerPost.get("Learning Hash Map"));
}
}