Implement your own HashMap

Thoroughly understand the underlying principles of HashMap by implementing your own HashMap

  • JDK1.8 HashMap is implemented through array, linked list, and red-black tree structure
  • Understand its dynamic expansion, hash algorithm, the process of storing and removing elements

The code is simple to implement (no treeing, rehash):

public interface IMap<K,V> {
    
    

    void put(K k, V v);

    V get(Object k);

    void remove(Object k);

    int size();
}
public class MyHashMap<K ,V> implements IMap<K, V>{
    
    

    private final static int DEFAULT_CAPACITY = 1 << 3;
    private Node<K,V>[] table;
    private int size;


    static class Node<K,V> {
    
    
        final K k;
        V v;
        Node<K,V> next;

        public Node(K k, V v, Node<K, V> next) {
    
    
            this.k = k;
            this.v = v;
            this.next = next;
        }

        @Override
        public String toString() {
    
    
            return "Node{" +
                    "k=" + k +
                    ", v=" + v +
                    ", next=" + next +
                    '}';
        }
    }


    @Override
    public void put(K k, V v) {
    
    
        Node<K,V>[] tab;
        Node<K,V> p;
        int i, n, h;
        //如果哈希表为null,在resize里面进行初始化
        if ((tab = table) == null || (n = table.length) == 0) {
    
    
            n = (tab = resize()).length;
        }
        //元素下标对应的位置中没有元素,直接入桶
        if ((p = tab[i = ((h = hash(k)) & (n-1))]) == null) {
    
    
            tab[i] = new Node<>(k,v,null);
        }else {
    
    
            //否则发生哈希碰撞,进行判断k是否相同
            Node<K,V> e;
            K k1;
            int hash = hash(k1 = p.k);
            //与哈希桶中k相同,e!=null
            if (hash == h && (Objects.equals(k, k1))) {
    
    
                //Objects.equals(k, k1) -->  return (a == b) || (a != null && a.equals(b));
                e = p;
            }else {
    
    
                //将新元素连到链表中
                while (true) {
    
    
                    //链表中k不重复,e == null
                    if ((e = p.next) == null) {
    
    
                        p.next = new Node<>(k,v,null);
                        break;
                    }
                    //与链表中k相同,e!=null
                    if (hash(e.k) == h && Objects.equals(e.k,k)) {
    
    
                        break;
                    }
                    p = e;
                }
            }
            //k值相同,进行value的替换
            if (e != null) {
    
    
                e.v =v;
                //重复的k,size不进行++操作,直接return
                return;
            }
        }
        if (++size > table.length) {
    
    
            resize();
        }

    }

    private int hash(Object k) {
    
    
        return k == null ? 0 : k.hashCode() ^ (k.hashCode()>>>16);
        //return 1;
    }

    private Node<K,V>[] resize() {
    
    
        Node<K,V>[] oldTable = table;
         int oldCap = (oldTable == null) ? 0 : oldTable.length;
         int newCap = 0;
         if (oldCap > 0) {
    
    
             newCap = oldCap << 1;
         }else {
    
    
             newCap = DEFAULT_CAPACITY;
         }
         @SuppressWarnings("unchecked")
         Node<K,V>[] newTable = (Node<K,V>[])new Node[newCap];
         table = newTable;
         if (oldTable != null) {
    
    
             //rehash
             //waiting...
         }
         return newTable;

    }

    @Override
    public V get(Object k) {
    
    
        Node<K,V> e;
        return (e = getNode(hash(k),k)) == null ? null : e.v;
    }

    private Node<K,V> getNode(int hash, Object k) {
    
    
        if (table == null || table.length == 0 || table[hash&(table.length - 1)] == null) {
    
    
            return null;
        }
        Node<K,V> first = table[hash&(table.length - 1)];

        if (hash(first.k) == hash && Objects.equals(first.k,k)) {
    
    
            return first;
        }
        Node<K,V> e;
        if ((e = first.next) != null) {
    
    
            do {
    
    
                if (hash(e.k) == hash && Objects.equals(e.k,k)) {
    
    
                    return e;
                }

            }while ((e = e.next) != null);
        }
        return null;
    }

    @Override
    public void remove(Object k) {
    
    
        //waiting...

    }

    @Override
    public int size() {
    
    
        return size;
    }

    @Override
    public String toString() {
    
    
        return "MyHashMap{" +
                "table=" + Arrays.toString(table) +
                '}';
    }
}
  • Test Results:
public class Test {
    
    
    public static void main(String[] args) {
    
    
        MyHashMap<String,String> map = new MyHashMap<>();
        map.put("k1","v1");
        map.put("k2","v2");

        System.out.println(map.get("k1"));
        System.out.println(map.get("k2"));
        System.out.println(map.size());
        System.out.println(map);

        map.put("k2","vv");
        map.put("k3","v3");
        map.put("kk","vv");
        map.put("k1",null);
        System.out.println(map.get("k2"));
        System.out.println(map.get("k1"));
        System.out.println(map.size());
        System.out.println(map);
        map.put(null,null);
        System.out.println(map.size());
        System.out.println(map);

        /**
         * 结果:
         * v1
         * v2
         * 2
         * MyHashMap{table=[null, null, null, null, null, null, Node{k=k1, v=v1, next=null}, Node{k=k2, v=v2, next=null}]}
         * vv
         * null
         * 4
         * MyHashMap{table=[Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=null}}, null, null, null, null, null, Node{k=k1, v=null, next=null}, Node{k=k2, v=vv, next=null}]}
         * 5
         * MyHashMap{table=[Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=Node{k=null, v=null, next=null}}}, null, null, null, null, null, Node{k=k1, v=null, next=null}, Node{k=k2, v=vv, next=null}]}
         *
         *
         */

        /**
         * 测试哈希碰撞结果:(将hash()直接return 1;)
         * v1
         * v2
         * 2
         * MyHashMap{table=[null, Node{k=k1, v=v1, next=Node{k=k2, v=v2, next=null}}, null, null, null, null, null, null]}
         * vv
         * null
         * 4
         * MyHashMap{table=[null, Node{k=k1, v=null, next=Node{k=k2, v=vv, next=Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=null}}}}, null, null, null, null, null, null]}
         * 5
         * MyHashMap{table=[null, Node{k=k1, v=null, next=Node{k=k2, v=vv, next=Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=Node{k=null, v=null, next=null}}}}}, null, null, null, null, null, null]}
         *
         */

    }

Guess you like

Origin blog.csdn.net/Beer_xiaocai/article/details/104955389