t0mcat
t0mcat

Reputation: 5669

Custom HashMap implementation

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

Answers (8)

Deepika Kumari
Deepika Kumari

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

Govind Sharma
Govind Sharma

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

Ashish Shetkar
Ashish Shetkar

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

bhargavi damodaran
bhargavi damodaran

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

user2489036
user2489036

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

java_mouse
java_mouse

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

Mike Axiak
Mike Axiak

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

willcodejavaforfood
willcodejavaforfood

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

Related Questions