手写迷你版HashMap

       最近看了一些面试题,感觉网上好像有挺多公司比较喜欢让面试者手写HashMap,说实话理解JDK HashMap源码还是很需要时间的。打开看了一下HashMap源代码,将近2400行代码,前两位作者乃大名鼎鼎Doug LeaJosh Bloch,普通人确实无法匹及。好了,废话不多说了,今天写了一个迷你版HashMap,只包含putget方法,当然这两个方法应该是HashMap中使用频率最高的两个了,理解了put、get方法,后续增加size、remove方法应该不难,同时这里也没有做多线程锁处理,因为是迷你版,尽量帮助理解即可。

下面是源码:

package cn.crabime.redis;

import java.util.ArrayList;
import java.util.List;

public class MyHashMap<K, V> implements MyMap<K, V> {

    static class MyEntry<K, V> implements Entry<K, V> {
        K k;
        V v;
        MyEntry<K, V> next;

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

        public K getKey() {
            return this.k;
        }

        public V getValue() {
            return this.v;
        }
    }

    private int defaultLength; //默认长度
    private double defaultFactor;
    private double useSize;
    private MyEntry<K, V>[] table;

    public MyHashMap() {
        this(16, 0.75);
    }

    public MyHashMap(int defaultLength, double defaultAddFactor) {
        this.defaultLength = defaultLength;
        this.defaultFactor = defaultAddFactor;
        if (defaultLength < 0) {
            throw new IllegalArgumentException("传入长度不合理");
        }
        if (defaultAddFactor < 0) {
            throw new IllegalArgumentException("传入负载因子不合理");
        }
        table = new MyEntry[defaultLength];
    }

    public V put(K k, V v) {
        // 如果当前数组元素个数超过指定值,则需要扩容
        if(useSize > defaultLength * defaultFactor) {
            dilatation();
        }
        int index = getIndex(k, table.length);
        System.out.println("k=[" + k + "],index=[" + index + "]");
        // 拿到table数组中当前index值
        MyEntry<K, V> currentEntry = table[index];
        // 将当前k/v构建一个待插入的Entry
        MyEntry<K, V> nextEntry = new MyEntry<K, V>(k, v, null);
        if (currentEntry == null) {
            table[index] = nextEntry;
            useSize++;
        } else {
            if (currentEntry.getKey() == k || (currentEntry.getKey() != null && currentEntry.getKey().equals(k))) {
                currentEntry.v = v;
            } else {
                while (currentEntry.next != null) {
                    if (currentEntry.next.getKey() == k || (currentEntry.next.getKey() != null && currentEntry.next.getKey().equals(k))) {
                        currentEntry.next.v = v;
                        break;
                    } else {
                        currentEntry = currentEntry.next;
                    }
                }
                if (currentEntry.next == null) {
                    currentEntry.next = nextEntry;
                }
            }
        }
        return nextEntry.getValue();
    }

    public V get(K k) {
        int index = getIndex(k, table.length);
        MyEntry<K, V> currentEntry = table[index];
        if (currentEntry != null) {
            // 从index处的链表中获取值
            while (currentEntry != null) {
                if (currentEntry.getKey() == k || (currentEntry.getKey() != null && currentEntry.getKey().equals(k))) {
                    return currentEntry.getValue();
                } else {
                    currentEntry = currentEntry.next;
                }
            }
        }
        return null;
    }

    // 扩容
    private void dilatation() {
        System.out.println("开始进行扩容了...");
        MyEntry<K, V>[] newTable = new MyEntry[defaultLength * 2];
        List<MyEntry<K, V>> totalList = new ArrayList<MyEntry<K, V>>();
        for (int i = 0; i < table.length; i++) {
            if (table[i] == null) {
                continue;
            }
            MyEntry<K, V> entry = table[i];
            // 将所有的Entry添加到集合中
            while (entry != null) {
                totalList.add(entry);
                entry = entry.next;
            }
        }

        if (totalList.size() > 0) {
            useSize = 0;
            defaultLength = defaultLength * 2;
            table = newTable;
            for (MyEntry<K, V> myEntry : totalList) {
                if (myEntry.next != null) {
                    myEntry.next = null;
                }
                put(myEntry.getKey(), myEntry.getValue());
            }
        }
    }

    private int getIndex(K k, int length) {
        int m = length - 1;
        // 这里用的位运算做取模操作,如果用%符号取模,那m=length而不是length-1
        int index = hash(k) & m;
        return index > 0 ? index : -index;
    }

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

    public static void main(String[] args) {
        MyHashMap<String, String> map = new MyHashMap<String, String>();
        map.put("dDkMALcfRH", "5");
        map.put("dbgheYdIdX", "14");
        map.put("NxHFwVKWnk", "13");
        map.put("DBBDCshUAH", "1");
        map.put("ntJlqxeUBr", "9");
        map.put("olQRqXGPvc", "9");
        map.put("kVcpPJZnPx", "0");
        map.put("pNofFlvYck", "3");
        map.put("xmfOhdCmzX", "15");
        map.put("sNLsIPKtvZ", "12");
        map.put("JQFIaxJiub", "2");
        map.put("kYUvuqybBq", "4");
        map.put("dDvgWhskYh", "6");
        map.put("pESrWwnmtG", "7");
        map.put("NEElevYhuE", "8");

        System.out.println("key=dDkMALcfRH, value=" + map.get("dDkMALcfRH"));
        System.out.println("key=JQFIaxJiub, value=" + map.get("JQFIaxJiub"));
    }
}

MyMap接口信息如下:

package cn.crabime.redis;

public interface MyMap<K, V> {
    public V put(K k, V v);

    public V get(K k);

    interface Entry<K, V> {
        public K getKey();

        public V getValue();
    }

}

输出结果如下:

k=[dDkMALcfRH],index=[5]
k=[dbgheYdIdX],index=[14]
k=[NxHFwVKWnk],index=[13]
k=[DBBDCshUAH],index=[1]
k=[ntJlqxeUBr],index=[9]
k=[olQRqXGPvc],index=[9]
k=[kVcpPJZnPx],index=[0]
k=[pNofFlvYck],index=[3]
k=[xmfOhdCmzX],index=[15]
k=[sNLsIPKtvZ],index=[12]
k=[JQFIaxJiub],index=[2]
k=[kYUvuqybBq],index=[4]
k=[dDvgWhskYh],index=[6]
k=[pESrWwnmtG],index=[7]
开始进行扩容了...
k=[ntJlqxeUBr],index=[9]
k=[NEElevYhuE],index=[8]

参考地址:https://www.jianshu.com/p/2e585189423e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值