純手寫實現HashMap

1.hashmap的實現node

  ① 初始化數組

    1)定義一個Node<K, V>的數組來存放元素,但不當即初始化,在使用的時候再加載ide

    2)定義數組初始大小爲16測試

    3)定義負載因子,默認爲0.75,this

    4)定義size用來記錄容器存放的元素數量spa

  ② put的實現思路code

    1)  判斷容器是否爲空,爲空則初始化。對象

    2)判斷容器的size是否大於閥值,是的話就擴容爲之前長度的兩倍,並從新計算其中元素的存放位置,進行從新存放blog

    3)計算出key的index角標位置get

    4)判斷計算出的index位置是否存在元素,存在的話則遍歷鏈表,判斷key是否存在,存在則更新,不存在則增長

  ③ get的實現思路

    1)經過key計算出它所在的index

    2)遍歷index位置處的鏈表,並獲取value返回。

package com.test;

/**
 * 自定義hashMap
 * @author cf
 *
 * @param <K>
 * @param <V>
 */
public class MyHashMap<K, V> implements MyMap<K, V>{
    //1.定義一個容器用來存放元素, 但不當即初始化,使用懶加載方式
    Node<K, V>[] table = null;
    
    //2.定義容器的默認大小
    static int DEFAULT_INITIAL_CAPACITY = 16;
    
    //3.HashMap默認負載因子,負載因子越小,hash衝突機率越低,綜合結論得出0.75最爲合適
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    
    //4.記錄當前容器實際大小
    static int size;
    
    @SuppressWarnings("unchecked")
    @Override
    public V put(K k, V v) {
        //1.判斷容器是否爲空爲空則初始化。
        if (table == null) {
            table = new Node[DEFAULT_INITIAL_CAPACITY];
        }
        
        //若是size大於閾值則進行擴容
        if (size > DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR) {
            resize();
        }
        
        //2.計算出index角標
        int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
        
        //3.將k-v鍵值對放進相對應的角標,若是計算出角標相同則以鏈表的形勢存放
        Node<K, V> node = table[index];
        if (node == null) {
            table[index] = new Node<>(k, v, null);
            size ++;
            return table[index].getValue();
        } else {
            Node<K, V> newNode = node;
            
            //循環遍歷每一個節點看看是否存在相同的key
            while (newNode != null) {
                //這裏要用equals 和 == 由於key有多是基本數據類型,也有多是引用類型
                if (k.equals(newNode.getKey()) || k == newNode.getKey()) {
                    newNode.setValue(v);
                    size ++;
                    return v;
                } 
                newNode = node.getNextNode();
            }
            table[index] = new Node<K, V>(k, v, table[index]);
            size ++;
            
            return table[index].getValue();
        }
        
    }
    
    /**
     * 獲取index
     * @param key
     * @param length
     * @return
     */
    public int getIndex(K key, int length) {
        int hashCode = key.hashCode();
        int index = hashCode % length;
        return index;
    }

    /**
     * 獲取key
     */
    @Override
    public V get(K k) {
        int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
        Node<K, V> node = table[index];
        if (k.equals(node.getKey()) || k == node.getKey()) {
            return node.getValue();
        } else {
            Node<K, V> nextNode = node.getNextNode();
            while(nextNode != null) {
                if (k.equals(nextNode.getKey()) || k == nextNode.getKey()) {
                    return nextNode.getValue();
                }
            }
        }
        return null;
    }
    
    /**
     * 對size進行擴容
     */
    @SuppressWarnings("unchecked")
    public void resize() {
        //1.建立新的table長度擴展爲之前的兩倍
        int newLength = DEFAULT_INITIAL_CAPACITY * 2;
        Node<K, V>[] newtable = new Node[newLength];
        //2.將之前table中的取出,並從新計算index存入
        for (int i = 0; i < table.length; i++) {
            Node<K, V> oldtable = table[i];
            while (oldtable != null) {
                //將table[i]的位置賦值爲空,
                table[i] = null;
                
                //方法1:從新計算index,而後按照put時候的方法進行放值,此種方法會不停的new 對象會形成效率比較低
                /*K key = oldtable.getKey();
                int index = getIndex(key, newLength);
                newtable[index] = new Node<K, V>(key, oldtable.getValue(), newtable[index]);
                oldtable = oldtable.getNextNode();*/
                
                //方法2:
                //計算新的index值
                K key = oldtable.getKey();
                int index = getIndex(key, newLength);
                
                //將之前的nextnode保存下來
                Node<K, V> nextNode = oldtable.getNextNode();
                
                //將newtable的值賦值在oldtable的nextnode上,若是之前是空,則nextnode也是空
                oldtable.setNextNode(newtable[index]);
                newtable[i] = oldtable;
                
                //將之前的nextcode賦值給oldtable以便繼續遍歷
                oldtable = nextNode;
            }
                
        }
        
        //3.將新的table賦值回老的table
        table = newtable;
        DEFAULT_INITIAL_CAPACITY = newLength;
        newtable = null;
        
    }

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

    @SuppressWarnings("hiding")
    class Node<K, V> implements Entry<K, V> {
        private K key;
        private V value;
        private Node<K, V> nextNode; //下一節點
        
        public Node(K key, V value, Node<K, V> nextNode) {
            super();
            this.key = key;
            this.value = value;
            this.nextNode = nextNode;
        }

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

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

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

        public Node<K, V> getNextNode() {
            return nextNode;
        }

        public void setNextNode(Node<K, V> nextNode) {
            this.nextNode = nextNode;
        }

        public void setKey(K key) {
            this.key = key;
        }
        
        //判斷是否還有下一個節點
        /*private boolean hasNext() {
            return true;
        }*/
        
    }
    
    
    
    // 測試方法.打印全部的鏈表元素
    public void print() {
        for (int i = 0; i < table.length; i++) {
            Node<K, V> node = table[i];
            System.out.print("下標位置[" + i + "]");
            while (node != null) {
                System.out.print("[ key:" + node.getKey() + ",value:" + node.getValue() + "]");
                node = node.nextNode;
            }
            System.out.println();
        }

    }
    
}

2.測試代碼

package com.test;

public class TestMap {
    public static void main(String[] args) {
        MyHashMap<String, String> extHashMap = new MyHashMap<String, String>();
        extHashMap.put("1號", "1號");// 0
        extHashMap.put("2號", "1號");// 1
        extHashMap.put("3號", "1號");// 2
        extHashMap.put("4號", "1號");// 3
        extHashMap.put("6號", "1號");// 4
        extHashMap.put("7號", "1號");
        extHashMap.put("14號", "1號");

        extHashMap.put("22號", "1號");
        extHashMap.put("26號", "1號");
        extHashMap.put("27號", "1號");
        extHashMap.put("28號", "1號");
        extHashMap.put("66號", "66");
        extHashMap.put("30號", "1號");
        System.out.println("擴容前數據....");
        extHashMap.print();
        System.out.println("擴容後數據....");
        extHashMap.put("31號", "1號");
        extHashMap.put("66號", "123466666");
        extHashMap.print();
        // 修改3號以後
        System.out.println(extHashMap.get("66號"));
        
    }
}

 

若有疑問或錯誤請在下方留言指出!  謝謝大佬

相關文章
相關標籤/搜索