java手写HashMap

手写HashMap

  • JDK1.7 的HashMap 是基于,数组和单向链表实现。大致原理是:当put的元素的时候,根据key的值和数组的大小,获取该元素在数组中存入的位置,如果当前位置是空,直接添加一个节点。反之,遍历链表进行添加或者修改。HashMap的扩容机制是,当容器内存储的元素个数大于,负载因子和数组的大小的乘积的时候,进行扩容,默认是2倍。并且需要重新,计算数组中的元素的位置。
package com.work.one.map;

/**
 * Created by 廖开雷 on 2020/2/4.
 */
public interface MyMap<K, V> {

    void put (K k, V v);

    V get (K k);

    V remove (K k);

    int size ();
}
package com.work.one.map.impl;

import com.work.one.map.MyMap;

/**
 *
 * Created by 廖开雷 on 2020/2/4.
 * hashMap 是基于 数组和单链表实现的 
 * 单链表只维护 当前节点的下一个元素
 * 为什么用单链表,是因为其实根本用不到 双链表中pre
 */
@SuppressWarnings("all")
public class LklHashMap<K, V> implements MyMap<K, V> {

    private int size = 0;

    private Entry[] tables;

    private float loadFactors = 0.75f;

    public LklHashMap(int initCapacity) {
        tables = new Entry[initCapacity];
    }

    @Override
    public void put(K k, V v) {
        //存储在数组中的位置
        int index = k.hashCode() % tables.length;

        // 直接放入吧
        Entry newEntry = new Entry(k, v);

        //判断目标位置是否存在元素,不存在则直接添加
        if (tables[index] == null) {
            tables[index] = newEntry;
            size ++ ;
        } else {
            Entry start = tables[index];
            //修改
            if (start.getK().equals(k) || start.getK() == k) {
                start.setV(v);
                return;
            }
            boolean hasKey = false;
            //修改
            Entry now = start;
            while (now != null) {
                if (now.getK().equals(k)) {
                    now.setV(v);
                    hasKey = true;
                    break;
                }
                now = now.next;
            }
            if (hasKey) {
                return;
            }

            System.out.println("hash crash,put the value in the first..");
            newEntry.next = start;
            tables[index] = newEntry;
            size ++ ;
        }
        //如果 map中存储的元素个数大于 数组的 长度和负载因子的乘积 则扩容
        if (size > tables.length * loadFactors) {
            resize();
        }
    }

    /**
     *
     * 扩容
     */
    private void resize () {
        System.out.println(" resize is begin....");
        int newCapacity = tables.length * 2;
        Entry<K, V>[] newTables = new Entry[newCapacity];
        for (int i = 0; i < tables.length; i++) {
            Entry<K, V> entry = tables[i];
            while (entry != null) {
                K k = entry.getK();
                V v = entry.getV();
                int newIndex = k.hashCode() % newTables.length;
                Entry<K, V> newEntry = new Entry<>(k, v);
                //放入新的数组的新位置
                Entry oldEnrty = newTables[newIndex];
                if (oldEnrty == null) {
                    newTables[newIndex] = newEntry;
                    size ++ ;
                } else {
                    // 存在的话就修改
                    boolean hasKey = false;
                    while (oldEnrty.next != null) {
                        if (oldEnrty.getK().equals(k)  || oldEnrty.getK() == k) {
                            oldEnrty.setV(v);
                            hasKey = true;
                            break;
                        }
                        oldEnrty = oldEnrty.next;
                    }
                    if (hasKey) {
                        continue;
                    }
                    //不存在的话就放入链表的头部
                    newEntry.next = oldEnrty;
                    newTables[newIndex] = newEntry;
                    size ++ ;
                }
                entry = entry.next;
            }
        }
        tables = newTables;
        System.out.println(" resize is end.... new capacity is : " + tables.length);
    }

    @Override
    public V get(K k) {
        int index = k.hashCode() % tables.length;
        Entry target = tables[index];

        if (target == null) {
            return null;
        }

        if (target.getK().equals(k)) {
            return (V)target.getV();
        }

        while (target.next != null) {
            Entry temp = target.next;
            if (temp.getK().equals(k)) {
                return (V)temp.getV();
            }
            target = target.next;
        }
        return null;
    }

    public void print () {
        for (int i = 0; i < tables.length ; i++) {
            Entry entry = tables[i];
            while (entry != null) {
                System.out.println("hashCode : "+ entry.getK().hashCode() % tables.length + ",key:" + entry.getK() + ",value:" + entry.getV());
                entry = entry.next;
            }
        }

    }

    @Override
    public V remove(K k) {
        return null;
    }

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

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

        public K getK() {
            return k;
        }

        public void setK(K k) {
            this.k = k;
        }

        public V getV() {
            return v;
        }

        public V setV(V v) {
            V old = this.v;
            this.v = v;
            return old;
        }
    }
}

测试:

package com.work.one.map.impl;
/**
 * Created by 廖开雷 on 2020/2/4.
 */
public class TestMap {

    public static void main(String[] args) {
        LklHashMap<String, String> map = new LklHashMap<>(16);

        map.put("1号", "aa1");
        map.put("2号", "bb2");
        map.put("3号", "cc3");
        map.put("4号", "dd4");
        map.put("5号", "dd5");
        map.put("6号", "dd6");
        map.put("7号", "dd7");
        map.put("12号", "dd12");
        //会发生hash碰撞
        System.out.println("1号".hashCode() % 16);
        System.out.println("12号".hashCode() % 16);
        System.out.println(map.get("a"));
        map.print();
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永不止步——

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值