Reputation: 5669
This question was asked to me in an interview. I think the only way to get best solution is SOF. So the question was "How would you implement a custom HashMap in java(Assume there is no such data structure called HashMap)". The only answer I could think of was by implementing Associative Arrays (but then again, Java doesnt have associative arrays). Could you experts please pour in your thoughts on this question?
Upvotes: 11
Views: 35514
Reputation: 1
Simple HashMap Implementation in java
// Implementation class
public class HashMapCustom<K, V>
{
static class Entry <K,V>{
K key;
V value;
Entry<K,V> next;
public Entry(K key, V value,Entry<K,V> next ){
this.key=key;
this.value=value;
this.next=next;
}
}
private Entry<K,V>[] bucket ;
private int capacity = 4;
public HashMapCustom(){
bucket = new Entry [capacity];
}
public void put(K key, V value){
if(null == key) return; // null keys not allowed
int hash = hash(key);
Entry<K,V> add = new Entry<K,V> (key,value,null);
if(bucket[hash]==null){
bucket[hash]=add;
}else{
Entry<K,V> curr = bucket[hash];
while(null !=curr){
if(curr.key.equals (key)){
curr.value =value;
return;
}else{
if(curr.next == null){
curr.next = add;
return;
}
curr = curr.next;
}
}
}
}
public V get(K key){
if(null == key) return null;
int hash = hash(key);
Entry<K,V> b = bucket[hash];
if(null == b) return null;
while(null !=b){
if(b.key.equals (key)){
return b.value;
}else{
b=b.next;
}
}
return null;
}
public boolean remove(K key){
if(null == key) return false;
int hash = hash(key);
Entry<K,V> b = bucket[hash];
if(null == b) return false;
Entry<K,V> prev = null;
while(null !=b){
if(b.key.equals (key)){
//delete
if(prev == null) { // first node to remove
bucket[hash]=b.next;
return true;
}else{
prev.next = b.next;
return true;
}
}else{
prev=b;
b =b.next;
}
}
return false;
}
private int hash (K key)
{
return Math.abs (key.hashCode ())%capacity;
}
}
// calling class
public class App
{
public static void main(String a[]){
HashMapCustom<Integer,Integer> map = new HashMapCustom<Integer,Integer> ();
map.put (1,99);
map.put (2,24);
map.put (6,32);
map.put (4,10);
map.put (10,12);
map.remove (2);
map.put (1,44);
System.out.println ( map.get (6));
System.out.println ( map.get (2));
System.out.println ( map.get (6));
System.out.println ( map.get (1));
}
}
Upvotes: 0
Reputation: 137
public class Entry {
protected final Object key;
protected Object value;
protected Entry next;
public Entry(Object k, Object v) {
this.key = k;
this.value = v;
}
public void setValue(Object v) {
this.value = v;
}
public Object getValue() {
return this.value;
}
public Object getKey() {
return this.key;
}
@Override
public String toString() {
return "Entry [key=" + key + ", value=" + value + ", next=" + next + "]";
}
}
public class OwnHashMap {
private static final int SIZE = 16;
private Entry tables[] = new Entry[SIZE];
public Entry get(Object k) {
int hash = k.hashCode() % SIZE;
hash=Math.abs(hash);
Entry e = tables[hash];
if (e != null) {
while (e.getKey().equals(k)) {
return e;
}
e = e.next;
}
return null;
}
public void put(Object k, Object v) {
int hash = k.hashCode() % SIZE;
hash=Math.abs(hash);
Entry e = tables[hash];
if (e != null) {
if (e.getKey().equals(k)) {
e.value = v;
} else {
while (e.next != null) {
e = e.next;
}
Entry entryOld = new Entry(k, v);
tables[hash] = entryOld;
}
} else {
Entry entryNew = new Entry(k, v);
tables[hash] = entryNew;
}
}
public void printMap() {
for(Entry m:tables) {
if(m!=null)
System.out.println(m.getKey()+" "+m.getValue());
}
}
public static void main(String[] args) {
OwnHashMap map = new OwnHashMap();
map.put("Vikas", 10);
map.put("Govind", 1);
map.put("Abhishek", 3);
map.put("Sandeep", 4);
map.printMap();
}
}
Output
Govind 1
Sandeep 4
Abhishek 3
Vikas 10
Upvotes: 0
Reputation: 1467
adding just one more approach - how about if we use set instead of hashMap in this way
Create a custom class called pair -
public class Pair {
private String key;
private Object Value;
public Pair(String key, Object value) {
this.key = key;
Value = value;
}
public String getKey() {
return key;
}
public Object getValue() {
return Value;
}
@Override
public int hashCode() {
return key.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pair other = (Pair) obj;
if (key != other.getKey())
return false;
return true;
}
}
and then you can directly use java Set as Hashmap
public static void main(String[] args) {
Set<Pair> set = new HashSet<Pair>();
set.add(new Pair("key1", "val1"));
set.add(new Pair("key2", "val2"));
set.add(new Pair("key1", "val3"));
// you can advanced for loop for looping over set
for (Pair pair : set) {
}
// with java 8 - you can also use streams over it
// set.stream().filter
// set.stream().anyMatch
// and some more methods can be directly used
}
With Java-8 Stream API - it will enable this to make some more operations easy and fast.
Just adding this as one more possible approach for custom hashmap -
Upvotes: 0
Reputation: 51
References: - http://javarevisited.blogspot.sg/2011/10/override-hashcode-in-java-example.html - http://javarevisited.blogspot.in/2011/02/how-to-write-equals-method-in-java.html
class Entry<K, V> {
K key;
V val;
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getVal() {
return val;
}
public void setVal(V val) {
this.val = val;
}
@Override
public int hashCode() {
int prime = 13;
int mul = 11;
if (key != null) {
int hashCode = prime * mul + key.hashCode();
return hashCode;
}
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass().getName() != o.getClass().getName()) {
return false;
}
Entry e = (Entry) o;
if (this.key == e.key) {
return true;
}
return false;
}
}
public class HashMapImpl<K, V> {
private float loadfactor = 0.75f;
private int capacity = 100;
private int size = 0;
private Entry<K, V> table[] = new Entry[capacity];
private int Hashing(int hashCode) {
int location = hashCode % capacity;
System.out.println("Location:"+location);
return location;
}
public int size() {
// TODO Auto-generated method stub
return this.size;
}
public boolean isEmpty() {
if(this.size == 0) {
return true;
}
return false;
}
public boolean containsKey(Object key) {
if(key == null) {
if(table[0].getKey() == null) {
return true;
}
}
int location = Hashing(key.hashCode());
Entry e = null;
try {
e = table[location];
}catch(NullPointerException ex) {
}
if(e!= null && e.getKey() == key) {
return true;
}
return false;
}
public boolean containsValue(Object value) {
for(int i=0; i<table.length;i++) {
if(table[i] != null && table[i].getVal() == value) {
return true;
}
}
return false;
}
public V get(K key) {
V ret = null;
if(key == null) {
Entry<K, V> e = null;
try{
e = table[0];
}catch(NullPointerException ex) {
}
if(e != null) {
return (V) e.getVal();
}
} else {
int location = Hashing(key.hashCode());
Entry<K, V> e = null;
try{
e = table[location];
}catch(NullPointerException ex) {
}
if(e!= null && e.getKey() == key) {
return (V)e.getVal();
}
}
return ret;
}
public V put(K key, V val) {
V ret = null;
if (key == null) {
ret = putForNullKey(val);
return ret;
} else {
int location = Hashing(key.hashCode());
if(location >= capacity) {
System.out.println("Rehashing required");
return null;
}
Entry<K, V> e = null;
try{
e = table[location];
}catch(NullPointerException ex) {
}
if (e!= null && e.getKey() == key) {
ret = (V) e.getVal();
} else {
Entry<K, V> eNew = new Entry<K,V>();
eNew.setKey(key);
eNew.setVal(val);
table[location] = eNew;
size++;
}
}
return ret;
}
private V putForNullKey(V val) {
Entry<K, V> e = null;
try {
e = table[0];
}catch(NullPointerException ex) {
}
V ret = null;
if (e != null && e.getKey() == null) {
ret = (V) e.getVal();
e.setVal(val);
return ret;
} else {
Entry<K, V> eNew = new Entry<K,V>();
eNew.setKey(null);
eNew.setVal(val);
table[0] = eNew;
size++;
}
return ret;
}
public V remove(K key) {
int location = Hashing(key.hashCode());
V ret = null;
if(table[location].getKey() == key) {
for(int i=location; i<table.length;i++) {
table[i] = table[i+1];
}
}
return ret;
}
public static void main(String[] args) {
HashMapImpl<Integer, String> hashMap = new HashMapImpl<Integer, String>();
hashMap.put(10, "Apple");
hashMap.put(1, "Orange");
hashMap.put(79, "Grape");
System.out.println("Val at 79 "+hashMap.get(79));
System.out.println("Val at 1 "+hashMap.get(1));
System.out.println("Val at 10 "+hashMap.get(10));
System.out.println("Val at 2 "+hashMap.get(2));
hashMap.put(null, "Pear");
System.out.println("Val at null "+hashMap.get(null));
System.out.println("Hashmap has key at null:"+hashMap.containsKey(null));
System.out.println("Hashmap has value at null:"+hashMap.containsValue("Pear"));
System.out.println("Size of Map:"+hashMap.size());
}
}
Upvotes: 5
Reputation: 21
public class ArrayAsHashMap {
Object [][] hashArr = new Object [10] [2];
public void put(HashObject key, String value){
int index = key.hashCode();
Object [] arr = {key, value};
hashArr[index] = arr;
}
public String get(HashObject key){
int index = key.hashCode();
Object [] arr = hashArr[index];
return (String)arr[1];
}
}
Upvotes: 2
Reputation: 2109
You should use one dimensional array. Object[] arr.
The index of the array is the normalized hashcode from the Key object. The array holds the Pair.
The reason the value consists of both Key and Value is that if there is any hash collision , it has to go thru the list of keys inside the slot and find out which is the correct key (using equals on the key object).
Upvotes: 0
Reputation: 11994
Look at Cliff Click's nonblockinghahmap for an example of a need for a hashmap implemented in java. Remember that an associated array is just another name for a hash map, so he's asking you how to implement it.
Generally hashes are implemented using standard arrays (not lists or anything fancy for speed). The issue is what is inside each of these arrays... in the case of a hash collision do you want to use a LinkedList (chaining) or do you want to rehash and go to another array location (open addressing). Read some more computer science to learn the cost/benefit to doing both.
Upvotes: 1
Reputation: 44063
Short Answer:
It would be an array of arrays (or Lists).
Object[][] map;
where map[bucketIndex]
would return the 'bucket'.
When inserting something you need a function to calculate bucketIndex
this would use the hashcode
of the inserted object.
Boom done!
:)
Upvotes: 8