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());
    }
}


免責聲明!

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



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