HashMap手写

public interface DIYMap<K,V> {
    public V put(K key, V value);
    public V get(K key);
    interface Entry<K,V> {
        Entry<?,?> next = null;
        public K getKey();
        public V getValue();
    }

}



package collection;

import java.util.ArrayList;

public class DIYHashMap<K,V> implements DIYMap<K,V>{
    // 定义初始化默认数组长度
    private int defaultLength  = 16;
    // 定义默认负载因子
    private double defaultAddSizeFactor = 0.75;

    // 使用数组位置的总数
    private int useSize;

    // 定义骨架Entry数组
    private Entry<K,V> [] table;

    // tableSize()函数为了保证数组长度是2的幂
    // 为了hash散列的时候保持均匀分布,提高空间的利用效率
    public int tableSizeFor(int n) {
        int num = n-1;
        num |= num>>>1;
        num |= num>>>2;
        num |= num>>>4;
        num |= num>>>8;
        num |= num >>>16;
        return (num<0) ? 1:((num>=1<<30)?1<<30:num+1);
    }

    public DIYHashMap(int defaultLength, double defaultAddSizeFactor) {
        if(defaultLength < 0) {
            throw new IllegalAccessError("数组长度为负数");
        }
        if(defaultAddSizeFactor <= 0 || Double.isNaN(defaultAddSizeFactor)) {
            throw new IllegalAccessError("扩容长度不能为非数字");
        }
        this.defaultLength = defaultLength;
        this.defaultAddSizeFactor = defaultAddSizeFactor;
    }

    public DIYHashMap() {}

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

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

        public V getValue() {
            return v;
        }
    }

    /**
     * 在put一个元素之前,先进行检查 查看当前已经使用的容量useSize是否超过了当前的负载因子,
     * 或者是没有进行数组分配.如果是,进行扩容,将数组初始化,或者两倍扩展
     *
     */
    @Override
    public V put(K key, V value) {
        //查看useSize是否超过了当前的负载因子
       if(table.length ==0 || useSize > defaultAddSizeFactor*defaultLength) {
            up2Size();
       }
        //求出需要put的元素被放置的索引getIndex() hash散列算法
       int index = getIndex(key,table.length);
        Entry<K,V> entry = table[index];
        // 构造一个新的Entry插入到Map中
        Entry<K,V> newEntry = new Entry<K,V>(key,value, null);
        // 索引为空  直接插入到数组中
        if(entry == null) {
            table[index] = newEntry;
            useSize++;
            //不为空 发生了hash冲突 需要将新值放在table[index].next位置
        } else {
            Entry<K,V> tmp;
            while ((tmp = table[index]) != null) {
                tmp = tmp.next;
            }
            tmp.next = newEntry;
        }
        return newEntry.getValue();
    }

    /**
     * 在up2Size()中,重点在于数据如何rehash,这里采用ArrayList将旧的所有元素导出,
     * 重新进行hash计算新的index进行导入到新的数组中
     */
    public void up2Size() {
        Entry<K,V> []  newTable = new Entry[defaultLength*2];
        ArrayList<Entry<K,V>> entryList = new ArrayList<Entry<K,V>>();
        for(int i=0;i<table.length;i++) {
            if(table[i]==null) {
                continue;
            }
            findEntryByNext(table[i],entryList);
        }
        if(entryList.size()>0) {
            useSize = 0;
            defaultLength = defaultLength*2;
            table = newTable;
            for(Entry<K,V> entry : entryList) {
                if(entry.next != null) {
                    entry.next = null;
                }
                put(entry.getKey(), entry.getValue());
            }
        } else {
                table = new Entry[defaultLength];
        }
    }

    public void findEntryByNext(Entry<K,V> entry, ArrayList<Entry<K,V>> entryList) {
        if(entry != null && entry.next != null) {
            entryList.add(entry);
            findEntryByNext(entry.next, entryList);
        } else {
            entryList.add(entry);
        }
    }

    // 这边的重点在于hash算法,保证分布均匀
    private int getIndex(K k, int length) {
        int m = length -1;
        int hashCode = k.hashCode();
        hashCode = hashCode^((hashCode>>>7)^(hashCode>>>12));
        hashCode = hashCode^((hashCode>>>7)^(hashCode>>>4));

        int index = hashCode & m;
        return index>=0 ? index:-index;
    }


    @Override
    public V get(K key) {
        return null;
    }
}

  

posted @ 2018-09-12 11:05  寅辰  阅读(78)  评论(0)    收藏  举报