zoukankan      html  css  js  c++  java
  • HashMap为什么效率高?来看看这个小demo

    一、前情回顾:在程序中有时候需要存放对象,容器应运而生。容器分为集合和Map。集合在这里不说,说说Map。Map在英语中是地图的意思,这个名字真是起的好,可以让人顾名思义。Map,就是存放键值对的结构。也就是说,只要找到键,就能找到对应的值,就跟查字典一样。

    二、Map工作效率的深层原理:

        1.上面说到查询map就是查询键,只要键找得到,值就会对应的找得到。所以怎么找到键,就是访问Map的效率的瓶颈所在。

        2.那么如何找到键呢?其中一个好办法就是把键排序,然后按照二分法查找。二分法就不用介绍了吧?

        3.散列(HashMap)则更进一步。他把键相关的信息保存在一个数组中。因为数组时访问速度最快的数据结构。这样可以大大提高效率。但是数组中存储的是键的相关信息,而不是键本身。因为Map的大小是不确定的,而数组的大小是确定的,所以问题来了,怎么把不确定size的Map的键的相关信息存储在数组中呢?

        4.那就是数组并不保存键本身,只保存于键相关的信息,这个相关信息就是每一个键对象生成的数字,将其作为数组的下表,这个数字就是散列码,即hashCode()方法。

        5.不同的键可以产生相同的散列码,对应于数组的相同下标。这样就解决了数组大小不变的问题。即:数组中的每一个具体的位置,可以根据Map的大小存储一个或多个Map基本元素,这样就会保证Map可以自由调节大小。Map小了,把数组填不满,Map大了,就往数组的同一个位置多填几个值。其数据结构如下图:

    代码如下

    package test;
    
    import java.util.Map;
    
    /**
     * @author 笑傲独行侠
     * @description:
     * @Date: 2019/7/9 13:55
     */
    public class MapEntry<K, V> implements Map.Entry<K, V> {
        private K key;
        private V value;
    
        public MapEntry(K key, V value) {
            this.key = key;
            this.value = value;
        }
    
        @Override
        public K getKey() {
            return key;
        }
    
        @Override
        public V getValue() {
            return value;
        }
    
        @Override
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }
    }
    package test;
    
    import java.util.*;
    
    /**
     * @author 笑傲独行侠
     * @description: 理解HashMap的深层原理
     * @Date: 2019/7/9 11:33
     */
    public class SimpleHashMap<K, V> extends AbstractMap<K, V> {
        static final int SIZE = 997;//定义数组的大小,尽量大一下,使得一个map尽量存入不同的下标数组中
        LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];//定义一个数组,存放键的相关信息,数组中是List
    
        public V put(K key, V value) {
            V oldValue = null;
            //先计算key的hashCode值,再处理一下算出对应的数组下标
            int index = Math.abs(key.hashCode()) % SIZE;
    
            //如果该下标对应的还没有值,就先new一个List
            if (buckets[index] == null) {
                buckets[index] = new LinkedList<MapEntry<K, V>>();
            }
    
            //如果该下标已经有一个key存放在其中,就将当前key添加到该List中。
            LinkedList<MapEntry<K, V>> bucket = buckets[index];
            MapEntry<K, V> pair = new MapEntry<K, V>(key, value);
            boolean found = false;
            ListIterator<MapEntry<K, V>> it = bucket.listIterator();
            while (it.hasNext()) {
                MapEntry<K, V> iPair = it.next();
                if (iPair.getKey().equals(key)) {
                    oldValue = iPair.getValue();
                    it.set(pair);
                    found = true;
                    break;
                }
            }
            //定义一个Boolean变量,如果要存入的键已经存在,则替换该键对应的值,如果不存在则添加
            if (!found)
                buckets[index].add(pair);
            return oldValue;
        }
    
        @Override
        public V get(Object key) {
            int index = Math.abs(key.hashCode()) % SIZE;
            if (buckets[index] == null)
                return null;
            for (MapEntry<K, V> iPair : buckets[index]) {
                if (iPair.getKey().equals(key))
                    return iPair.getValue();
            }
            return null;
        }
    
        @Override
        public Set<Entry<K, V>> entrySet() {
            Set<Map.Entry<K, V>> set = new HashSet<>();
            for (LinkedList<MapEntry<K, V>> bucket : buckets) {
                if (bucket == null) {
                    continue;
                }
                for (MapEntry<K, V> mPair : bucket) {
                    set.add(mPair);
                }
            }
            return set;
        }
    
        public static void main(String[] args) {
            SimpleHashMap<String, String> m = new SimpleHashMap<>();
            m.put("111", "huhhu");
            m.put("111", "huhhu");
            m.put("111", "huhhu");
            m.put("111", "huhhu");
            System.out.println(m);
            System.out.println(m.get("ERITREA"));
            System.out.println(m.entrySet());
        }
    }
  • 相关阅读:
    iaf——接口自动化测试框架
    性能优化系列
    MVC架构简介及其测试策略
    10种常见的软件架构模式
    软件开发框架分析和架构模式
    安全测试基础&安全测试---AppScan扫描工具
    WEB安全测试要点总结
    大数据Hadoop Hive HBase Spark Storm
    第三方授权方式1
    java-weixin-tools接入微信
  • 原文地址:https://www.cnblogs.com/xiaoao/p/11157493.html
Copyright © 2011-2022 走看看