美文网首页
手写HashMap

手写HashMap

作者: CodeDuan | 来源:发表于2022-02-23 17:25 被阅读0次

一、概述

在前面的文章中,我们分析了Map的原理,在弄清楚它的原理后,本文中我们来进行实践,手写一个简单的HashMap。

二、手写HashMap

  1. 手写一个HashMap必然要有插入,和查找的功能,所以我们先定义一个接口,定义插入和查找的方法。额外再加一个获取数量的方法。
public interface Map<K,V> {
    V put(K k,V v);
    V get(K k);
    int size();
}
  1. 我们都知道,HashMap底层用的是数组+链表,所以我们在Map中再定义一个Node节点的接口,用来存储数据。
public interface Map<K,V> {
    V put(K k,V v);
    V get(K k);
    int size();


    interface Node<K,V>{
        K getKey();
        V getValue();
    }
}
  1. 接口定义好之后 我们来写具体实现HashMap类。
public class HashMap<K,V> implements Map<K,V>{
    //创建数组
    private Node<K,V> table[];
    //数组长度
    final int LENGHT = 16;
    //元素长度
    private int size = 0;

    public HashMap() {
        table = new Node[LENGHT];
    }

    /**
     * 通过key 算出hash
     * 算出index
     * 判断node[index]是否为空
     * 不为空直接插入
     * 不为空赋值给next
     * @param k
     * @param v
     * @return v
     */
    @Override
    public V put(K k, V v) {
        //计算index
        int index = (LENGHT - 1) & hash(k);
        //拿到node对象
        Node<K,V> node = table[index];
        //如果node为空,说明数组中还没有,直接存入数组[index]
        if (node==null){
            table[index] = new Node<>(k,v,hash(k),null);
            size++;
        }else {
            //node不为空,说明数组中已经有了,直接赋值给next,头插
            table[index] = new Node<>(k,v,hash(k),node);
            size++;
        }
        return v;
    }

    /**
     * 通过k算出hash
     * 算出index
     * 找到对应的Node
     * 判断Node是否为空
     * 不为空 判断是否相等
     * 相等:返回
     * 不相等:继续查找
     * @param k
     * @return
     */
    @Override
    public V get(K k) {
        if (size==0) return null;
        //计算index
        int index = (LENGHT - 1) & hash(k);
        //拿到node对象
        Node<K,V> node = table[index];
        if (node!=null){
            //如果第一个node相等,直接返回
            if (node.hash==hash(k) && k.equals(node.getKey())){
                return node.getValue();
            }else {
                do{
                    if (node.next.hash==hash(k) && k==node.getKey()){
                        return node.next.getValue();
                    }
                }while (node.next!=null);
            }
        }
        return null;
    }

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

    //计算hash值
    private int hash(K k){
        return k.hashCode() ^ (k.hashCode()>>>16);
    }

    class Node<K,V> implements Map.Node<K,V>{

         K k;
         V v;
         int hash;
         Node<K,V> next;

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

        @Override
        public K getKey() {
            return k;
        }

        @Override
        public V getValue() {
            return v;
        }
    }
}

代码不是很难理解,这里简单讲一下,首先定义一个hash方法,算出key的hash,再通过key的hash与数组长度进行&运算得到下标。

put:,判断数组中这个位置是否已经存在元素,如果没有元素,则直接赋值给table[index]。如果已经有元素,则将数组中元素直接赋值给当前元素的next,这叫头插法。即插在链表的头部。

get:原理相同,同样是拿到index,然后判断hash和key是否相等,相等则返回,不相等则遍历链表继续查找。

三、测试

手写完毕,我们最后来进行测试,循环插入10条数据,并打印出来:

        HashMap<String,String> map = new HashMap<>();
        for (int i=0;i<10;i++){
            map.put("我是Key"+i,"我是Value"+i);
            System.out.println(map.get("我是Key"+i));
        }
         System.out.println(map.size());

        输出:
        我是Value0
        我是Value1
        我是Value2
        我是Value3
        我是Value4
        我是Value5
        我是Value6
        我是Value7
        我是Value8
        我是Value9
        10

最后可能会有同学问了,为什么没有写remove方法呢?当然是想让你们自己动手写啦,光看是看不会的,还是得动手敲起来,所以remove方法可以自己尝试着去写哦,其实remove和get原理类似,同样是先找到要删除的元素,如果要删除的元素的next不为空,则将next赋值给上一个元素的next,断开要删除元素的链,而达到删除的效果。快行动起来吧。

相关文章

网友评论

      本文标题:手写HashMap

      本文链接:https://www.haomeiwen.com/subject/umoolrtx.html