手寫hashmap

定義一個map接口

/**
 * Created by jiangcaijun on 2017/6/8.
 * 定義一個map的接口
 */
public interface CustomMap<K,V> {
    V put(K key,V value);

    V get (K key);

    int size();

    //定義一個內部接口
    //能夠根據Entry對象拿到這個對象的key和value
    interface Entry<K,V>{
        K getKey();
        V getValue();
    }
}

hashmap類,實現該map接口

/**
 * Created by jiangcaijun on 2017/6/8.
 * 定義一個customMap的實現類
 */
public class CustomHashMap<K,V> implements CustomMap<K,V> {

    private static Integer defaultLength = 16;//定義數組長度(定義成2的倍數)

    private static float defaultLoad=0.75F;//定義負載因子(超過這個因子就會擴容)

    private Entry<K,V>[] table =null;//定一個數組,盛放Entry對象

    private int size=0;//定義一個常量,用來記錄hashmap元素個數

    public CustomHashMap(){
        this(defaultLength,defaultLoad);
    }
    public CustomHashMap(int length, float load){
        if(length < 0){
            throw new IllegalArgumentException("Illegal length" + length);
        }
        if(load > 0.0F && !Float.isNaN(load)) {
            this.defaultLoad = load;
            this.defaultLength = length;
            table = new Entry[defaultLength];
        } else {
            throw new IllegalArgumentException("Illegal load: " + load);
        }
    }
    @Override
    public V put(K key, V value) {
        int index = getIndex(key,table.length);
        Entry<K,V> entry = table[index];
        if(entry == null){
            table[index] = new Entry(key,value,null,index);
        }else if(entry != null){
            table[index] = new Entry(key,value,entry,index);
        }
        size++;
        if(size > defaultLength*defaultLoad){
            resize();
        }
        return table[index].getValue();
    }


    @Override
    public V get(K key) {
        int index = getIndex(key,table.length);
        if(table[index] == null){
            return null;
        }
        return foundValueByKey(key,table[index]);
    }

    private V foundValueByKey(K key, Entry<K, V> entry) {
        if( key == entry.getKey() || key.equals(entry.getKey())){
            return entry.getValue();
        }else if(entry.next != null){
            return foundValueByKey(key,entry.next);
        }
        return null;
    }

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

    class Entry<K,V> implements CustomMap.Entry<K, V>{
        K key;
        V value;
        Entry<K,V> next;

        int index;//記錄下標

        Entry(K k,V v,Entry<K,V> n,int inx){
            key=k;
            value=v;
            index=inx;
            next=n;//數組第一個元素的下一個元素
        }

        public K getKey(){
            return key;
        }

        public V getValue(){
            return value;
        }
    }
    private int getIndex(K key, int length){
        int m = length -1 ;
        return key.hashCode() & m; //數值上等於key.hashCode() % length
    }
    //hashmap擴容
    private void resize() {
        Entry<K,V>[] newTable = new Entry[2*defaultLength];
        transfer(newTable);
    }

    private void transfer(Entry<K, V>[] newTable) {
        System.out.println("transfer 擴容");

        Entry[] src = table;                   //src引用了舊的Entry數組
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) { //遍歷舊的Entry數組
            Entry<K,V> e = src[j];             //取得舊Entry數組的每一個元素
            if (e != null) {
                src[j] = null;//釋放舊Entry數組的對象引用(for循環後,舊的Entry數組再也不引用任何對象)
                do {
                    Entry<K,V> next = e.next;
                    int i = getIndex(e.key, newCapacity); //從新計算每一個元素在數組中的位置
                    e.next = newTable[i]; //newTable[i]的引用賦給了e.next,也就是使用了單鏈表的頭插入方式,同一位置上新元素總會被放在鏈表的頭部位置;這樣先放在一個索引上的元素終會被放到Entry鏈的尾部(若是發生了hash衝突的話);
                    newTable[i] = e;      //將元素放在數組上
                    e = next;             //訪問下一個Entry鏈上的元素
                } while (e != null);
            }
        }
        table = newTable;
        defaultLength = 2*defaultLength;  //更新數組長度
    }
    public static void main (String[] args){
        CustomHashMap<String,String> map = new CustomHashMap<String,String>();
        for(int i = 0; i < 100; i++){
            map.put(i+"",i+"");
        }
        for(int i = 0; i < 100; i++){
            System.out.println("map取值: "+ i + " = "+map.get(i+""));
        }
    }
}

參考連接:

相關文章
相關標籤/搜索