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());
        }
    }
  • 相关阅读:
    轻重搭配
    EF的优缺点
    使用bootstrap-select有时显示“Nothing selected”
    IIS发布 HTTP 错误 500.21
    js添加的元素无法触发click事件
    sql server查看表是否死锁
    sql server把一个库表的某个字段更新到另一张表的相同字段
    SQLSERVER排查CPU占用高的情况
    SQL server中如何按照某一字段中的分割符将记录拆成多条
    LINQ to Entities does not recognize the method 'System.DateTime AddDays(Double)' method, and this method cannot be translated into a store expression.
  • 原文地址:https://www.cnblogs.com/xiaoao/p/11157493.html
Copyright © 2011-2022 走看看