zoukankan      html  css  js  c++  java
  • 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 FilesJavajdk1.8.0_211injava.exe" -Xms2048m -Xmx2048m "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA Community Edition 2020.1.1libidea_rt.jar=56358:C:Program FilesJetBrainsIntelliJ IDEA Community Edition 2020.1.1in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_211jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_211jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_211jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_211jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_211jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_211jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_211jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_211jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_211jrelibext
    ashorn.jar;C:Program FilesJavajdk1.8.0_211jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_211jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_211jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_211jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_211jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_211jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_211jrelibjce.jar;C:Program FilesJavajdk1.8.0_211jrelibjfr.jar;C:Program FilesJavajdk1.8.0_211jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_211jrelibjsse.jar;C:Program FilesJavajdk1.8.0_211jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_211jrelibplugin.jar;C:Program FilesJavajdk1.8.0_211jrelib
    esources.jar;C:Program FilesJavajdk1.8.0_211jrelib
    t.jar;F:workspacelinked_learnoutproductionlinked_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
    
  • 相关阅读:
    Java中四种XML解析技术
    Android ui utils简单实用的Android界面工具
    Android SAX解析xml文件
    Android SAX解析XML
    《Unix & Linux 大学教程》 第一、二章 学习笔记
    Eclipse设置背景色
    Java中getResourceAsStream的用法
    Android中asset文件夹和raw文件夹区别
    《Unix & Linux 大学教程》 第三、四章 学习笔记
    Android SAX解析实例教程
  • 原文地址:https://www.cnblogs.com/linma/p/13144060.html
Copyright © 2011-2022 走看看