用数组加链表实现一个Simple版的HashMap(暂未实现自动扩容)

目录

HashMap介绍

开始实现


HashMap介绍

HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

HashMap采取数组加链表的存储方式来实现,数组里的每个元素都是单向链表( Entry(key, value, next) ),

我们都知道数组查询效率高,但是增删效率低,而链表增删效率高,而查询效率低;也正是因为这一特性,HashMap采用的是数组加链表的结构;

不过,数组结构存储区间连续,占用内存情况较为严重,而链表结构存储区间较为离散,占有内存比较宽松;所以在JDK1.8之后,HashMap引入了红黑树的结构,当链表长度超过一定值(默认为8)时,则会将链表结构进行调整转变为红黑树结构;当红黑树中的元素数量小于8个时,则又会将结构体进行转变为链表结构;

HashMap的默认初始容量为16,即在创建一个HashMap时,HashMap首先创建一个长度为16的空数组,当我们插入数据时,会根据插入的Key进行hash计算,得出当前数据应该存储在数组的链表位置下标。

官方的hash函数运算代码:

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

简单一点讲,HashMap就是一个Entry数组,

private Entry<K, V>[] table;

每一个Entry包含一个key-value键值对(Entry就是HashMap里实现的一个静态内部类,里面定义了key、value等属性)

static class Entry<K, V> implements Map.Entry<K,V> {
        private final long hash;
        private final K key;
        private V value;
        Entry<K,V> next;

        Entry(long hash, K key, V value, Entry<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
}

大致的数据结构如下图(是不是很像一个表格):

 

基础的Bean属性:

Hash:当前位置Key的Hash值

Key:当前位置的键值

Value:当前位置存储的值

Next:下一个Entry对象

开始实现

实现方向:根据key的Hash值,计算得到Entry<K, V>数组的索引值,(这里的hash值理解成每个Key的hash都是固定的值就可以了)

取出第一个Entry对象,通过equals方法判断key是否相同,相同返回,不相同则取next值(下一个Entry对象)继续比较;直到相等或者next为空时返回最终结果

下面自定义实现CustomHashMap的基本功能:

/**
 * @description {自定义HashMap}
 * @author xxxxx
 * @version 1.0
 * <p>
 * Create by xxxxxx on 2020/12/15 15:00.
 */
public class CustomHashMap<K, V> implements Map<K, V>, Serializable {
    //默认容量
    private static int defaultLength = 16;
    //默认加载因子
    private static double defualtLoaderFactor = 0.75;
    private Entry<K, V>[] table;
    //键值对的数量
    private int size = 0;


    /**
     * 构造一个空的HashMap,指定的初始*容量和负载系数
     * @param length
     * @param loaderFactor
     */
    public CustomHashMap(int length, double loaderFactor) {
        defaultLength = length;
        defualtLoaderFactor = loaderFactor;
        table = new Entry[defaultLength];
    }

    public CustomHashMap() {
        this(defaultLength, defualtLoaderFactor);
    }

    /* ---------------- Static utilities -------------- */

    /**
     * 根据Key计算HashCode值
     * @param key
     * @return
     */
    private int hash(K key) {
        int m = defaultLength;
        int i = Objects.hashCode(key) % m;
        return i > 0 ? i : -i;
    }

    /**
     * 将Entry定义为成员内部类,定义Key-Value的存储结构,作为基本的Hash节点;
     * @param <K>
     * @param <V>
     */
    static class Entry<K, V> implements Map.Entry<K,V> {
        private final long hash;
        private final K key;
        private V value;
        //存储指向下一个Entry的引用,单链表结构
        Entry<K,V> next;

        Entry(long hash, K key, V value, Entry<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

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

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

        @Override
        public V setValue(V value) {
            return this.value = value;
        }

        @Override
        public String toString() {
            return "{key=" + key + ", value=" + value + ", nextKey="+ ((next != null) ? next.key : null) +"}";
        }
    }

    @Override
    public V put(K key, V value) {
        int index = hash(key);
        //根据key的hash值,数组长度计算该Entry<key,value>的数组下标
        Entry<K,V> entry = table[index];
        if(entry == null) {
            table[index] = new Entry<>(index, key, value, null);
            size ++;
        }else {
            //如果Key相同,新的Entry会覆盖旧的Entry
            table[index] = new Entry<>(index, key, value, entry);
        }
        return table[index].getValue();
    }

    @Override
    public V get(Object key) {
        K k = (K) key;
        int index = hash(k);
        if(table[index] == null) {
            return  null;
        }
        return findValue(table[index], k);
    }

    @Override
    public V remove(Object key) {
        K k = (K) key;
        int index = hash(k);
        if (table[index] != null){
            removeEntry(table[index], k);
        }
        return null;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {

    }

    @Override
    public void clear() {

    }

    @Override
    public Set<K> keySet() {
        return null;
    }

    @Override
    public Collection<V> values() {
        return null;
    }

    @Override
    public Set<Map.Entry<K, V>> entrySet() {
        return null;
    }

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

    @Override
    public boolean isEmpty() {
        return size <= 0;
    }

    @Override
    public boolean containsKey(Object key) {
        K k = (K) key;
        int index = hash(k);
        if(table[index] != null){
            V value = findValue(table[index], k);
            return !(null == value);
        }
        return false;
    }

    /**
     * 查找Value只能一个个链表去遍历
     * @param value
     * @return
     */
    @Override
    public boolean containsValue(Object value) {
        V v;
        Entry<K, V>[] tab = table;
        if(tab != null && size > 0){
            for (int i = 0; i < tab.length; ++i) {
                for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value || (value != null && value.equals(v)))
                        return true;
                }
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return "CustomHashMap{" +
                "table=" + Arrays.toString(table) +
                "\n, size=" + size +
                '}';
    }

    /**
     * 根据Key递归查找指定的Entry
     * @param entry
     * @param key
     * @return
     */
    public V findValue(Entry<K, V> entry, K key){
        if(Objects.equals(key, entry.key)){
            return entry.value;
        }else{
            if (!Objects.isNull(entry.next)){
                return findValue(entry.next, key);
            }
        }
        return null;
    }

    /**
     * 递归Entry,删除指定的Key
     * @param entry
     * @param key
     * @return
     */
    public V removeEntry(Entry<K, V> entry, K key){
        if(Objects.equals(entry.key, key)){

        }
        return null;
    }

测试后发现有key计算后的hash值过大,超出默认的容量造成下标越界

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值