HashMap 數組+鏈表實現


手撕HashMap主要是為了能更好的理解HashMap的數據結構原理。只實現了 put、get、remove。

JDK 實現的實在太復雜。這個實現是實現最簡單的版本。后續如果有時間會逐一補上 自動擴容,數組+紅黑樹的實現。

前提條件

  1. 數組+鏈表有基本了解

實現邏輯

package com.company;

public class MaLinHashMap {

    private int arrayLength;
    private Node[] bucketArray;

    public MaLinHashMap() {
        this.arrayLength = 16;
        this.bucketArray = new Node[arrayLength];
    }

    public MaLinHashMap(int arrayLength) {
        this.arrayLength = arrayLength;
        this.bucketArray = new Node[arrayLength];
    }

    private class Node {
        private Object key;
        private Object value;
        private Node next;

        public Node(Object key, Object value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }

    public void put(Object key, Object value) {
        int index = getBucketArrayIndex(key);
        Node headNode = bucketArray[index];
        Node newNode = new Node(key, value, null);
        if (headNode == null) {
            bucketArray[index] = newNode;
        } else {
            while (true) {
                if (headNode.next == null) {
                    headNode.next = newNode;
                    break;
                }
                headNode = headNode.next;
            }
        }
    }

    public void remove(Object key) {
        int index = getBucketArrayIndex(key);
        Node head = bucketArray[index];
        Node prev = null;
        while (head != null) {
            if (head.key.equals(key))
                break;
            prev = head;
            head = head.next;
        }
        if (head == null) {
            return;
        }
        if (prev != null) {
            prev.next = head.next;
        } else {
            bucketArray[index] = head.next;
        }
    }

    public Object get(Object key) {
        int index = getBucketArrayIndex(key);
        Node headNode = bucketArray[index];
        while (headNode != null) {
            if (headNode.key.equals(key)) return headNode.value;
            headNode = headNode.next;
        }
        return null;
    }

    /**
     * 獲取數組下標
     *
     * @param key 鍵
     * @return 下標
     */
    private int getBucketArrayIndex(Object key) {
        // 這里不采用 & 與運算符,直接使用hash%arrayLength可能出現負數非常尷尬。
        // return key.hashCode() % arrayLength;
        // TODO & 使用后可以確保得到一個 0~15 整數,但是位運算符實戰看不懂。這個還是抄襲的HashMap獲取index
        // if ((p = tab[i = (n - 1) & hash]) == null)
        int hash = (hash = key.hashCode()) ^ (hash >>> 16);
        return arrayLength - 1 & hash;
    }
}

測試邏輯

package com.company;

public class MaLinHashMapTest {
    public static void main(String[] args) {
        int count = 100000;
        test(32768, count);
        test(16384, count);
        test(8192, count);
        test(4096, count);
        test(2048, count);
        test(1024, count);
        test(512, count);
        test(256, count);
        test(128, count);
        test(64, count);
        test(32, count);
        test(16, count);
    }

    public static void test(int arrayLength, int count) {
        long start = System.currentTimeMillis();
        MaLinHashMap map = new MaLinHashMap(arrayLength);
        for (int i = 0; i < count; i++) {
            map.put("testKey" + i, i);
        }
        long timeConsuming = System.currentTimeMillis()-start;
        String output = String.format("數組長度%s, 數據量:%s, 耗時(毫秒): %s", arrayLength, count, timeConsuming);
        System.out.println(output);
    }
}

測試結果

"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" -Xms2048m -Xmx2048m "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.1.1\lib\idea_rt.jar=56358:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.1.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar;F:\workspace\linked_learn\out\production\linked_learn" com.company.MaLinHashMapTest
數組長度32768, 數據量:10000, 耗時(毫秒): 4
數組長度16384, 數據量:10000, 耗時(毫秒): 2
數組長度8192, 數據量:10000, 耗時(毫秒): 1
數組長度4096, 數據量:10000, 耗時(毫秒): 2
數組長度2048, 數據量:10000, 耗時(毫秒): 2
數組長度1024, 數據量:10000, 耗時(毫秒): 1
數組長度512, 數據量:10000, 耗時(毫秒): 2
數組長度256, 數據量:10000, 耗時(毫秒): 3
數組長度128, 數據量:10000, 耗時(毫秒): 6
數組長度64, 數據量:10000, 耗時(毫秒): 10
數組長度32, 數據量:10000, 耗時(毫秒): 18
數組長度16, 數據量:10000, 耗時(毫秒): 25

Process finished with exit code 0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM