IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Java之HashMap进阶 -> 正文阅读

[数据结构与算法]Java之HashMap进阶

对HashMap的数据结构和工作原理进行学习。

一、数据结构

随着版本的不同,HashMap的数据结构不同。

版本数据结构
jdk 1.7及以前数组+链表
jdk 1.8后数组+链表+红黑树

在这里插入图片描述

  • 数组
    HashMap的主干数据结构是数组,即key经过hash计算后将节点对象存放到数组对应的位置上
  • 链表
    当多个不同的key经过hash计算后得到的值相同,那么在数组对应位置上存储多个对象的链表,每个对象的属性除了key,value外还有next,即指向下一个节点的地址
  • 红黑树
    jdk1.8以后,如果某一条链表的长度超过8(默认),则转为红黑树的存储方式

二、工作原理

无参始化hashmap时,数组的初始容量16负载因子为0.75。容器的阈值等于 初始容量 × 负载因子,默认情况下阈值为 16 * 0.75 = 12;

2.1 put过程

第一步
hashMap使用自己的hash算法,算出传入的key的hash值;

第二步
用key的hash值调用indexOf()找到对象在数组中应该存放的位置;

第三步
当size(容器中已有Entry的数量)大于阈值时,进行扩容,将数组长度扩容为原来的2倍

第四步
将hash、key、value封装成一个Entry,存放到数组计算出来的位置中

  1. 位置无元素,放在该位置;
  2. 存在链表,则进行遍历,通过key进行equals比较:
    true:返回原来的value,将当前的value替换掉原来的
    false:将Entry对象的next指向改位置的初始节点(成为链表的第一个位置)

2.2 get过程

get过程的原理就比较简单,根据key的hashCode算出数组中的下标,遍历Entry链表,直到找到元素,源码如下:

/**
     * Returns the value to which the specified key is mapped,
     * or {@code null} if this map contains no mapping for the key.
     *
     * <p>More formally, if this map contains a mapping from a key
     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
     * key.equals(k))}, then this method returns {@code v}; otherwise
     * it returns {@code null}.  (There can be at most one such mapping.)
     *
     * <p>A return value of {@code null} does not <i>necessarily</i>
     * indicate that the map contains no mapping for the key; it's also
     * possible that the map explicitly maps the key to {@code null}.
     * The {@link #containsKey containsKey} operation may be used to
     * distinguish these two cases.
     *
     * @see #put(Object, Object)
     */
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);
 
        return null == entry ? null : entry.getValue();
    }
 
    /**
     * Offloaded version of get() to look up null keys.  Null keys map
     * to index 0.  This null case is split out into separate methods
     * for the sake of performance in the two most commonly used
     * operations (get and put), but incorporated with conditionals in
     * others.
     */
    private V getForNullKey() {
        if (size == 0) {
            return null;
        }
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }
/**
     * Returns the entry associated with the specified key in the
     * HashMap.  Returns null if the HashMap contains no mapping
     * for the key.
     */
    final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }
 
        int hash = (key == null) ? 0 : hash(key);
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }
  1. get的时候,如果key==null,判断Map的长度也为空的话就返回null,如果Map长度不为空,并且存在Entry,遍历table[0],返回e.value.
  2. getEntry的时候,首先要获取key的hash值,通过hash和table.length获取到的hashCode值得到entry在数组中存放的位置,如果传入的key与遍历的元素的key的hash相等的话并且key.equals为true,则返回entry;(如果返回的entry不为空的话,则返回entry的value值)。

2.3 负载因子

2.3.1 作用

用来计算阈值(初始容量 × 负载因子),当容量打到阈值时自动触发扩容机制。

2.3.2 为什么是0.75

这是时间和空间的权衡,是一个折中的选择。

  1. 负载因子太高,虽然提高了空间利用率,但是会导致大量的hash冲突,降低查询效率
  2. 当负载因子为0.5或者更低的时候,hash冲突降低从而提高了查询效率,但原本需要1M的存储空间,现在需要2M甚至更大的存储空间,结果就是空间利用率降低了。
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:48:16  更:2022-03-08 22:51:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:39:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码