记录Hashmap

103 阅读4分钟

概述

HashMap 提供了高效的键值对存储和检索方式,适用于需要快速访问和管理映射关系的多种场景,如数据库操作、缓存、索引等。它是现代编程中不可或缺的数据结构之一。

hashmap 数据结构组成:

1、 hash表:

哈希表(Hash Table),也称为散列表,是一种数据结构,用于存储键值对(key-value pairs)

哈希表的核心思想是利用哈希函数将键转换成唯一的索引,然后将该索引与值存储在数组中,以获取高效的查询。

2 、单链表:

每个节点除了包含存储的数据,还包含指向后一个节点的引用,hash冲突时挂载元素。

3、 红黑树:

红黑树(Red-Black Tree)是一种自平衡的二叉搜索树(Binary Search Tree),其设计思想是为了在有序集合(或映射)的基础上,提供高效的数据存储和检索,并且在插入和删除操作时保持树的平衡, 在某keY,hash冲突的元素大于等于8时由链表转成。

3.1 如何理解红黑的概念:

红黑树的 "红黑" 是指每个节点都被赋予了一个红色或黑色的标记,这些标记遵循一定的规则和性质,用以维护树的平衡和性能。红黑树的设计目标是保持树的高度平衡,以确保各种操作(插入、删除、查找等)在最坏情况下也能够在对数时间内完成。

规则: 根节点是黑色的,每个叶子节点(NIL 节点)都是黑色的,每个红色节点的两个子节点都是黑色的,从任一节点到其每个叶子的路径都包含相同数量的黑色节点,没有连续的红色节点,等等。

hashmap 核心成员变量:

  1. table(Node数组): 用于存储键值对的数组,是 HashMap 存储数据的主要容器。每个数组元素对应一个桶,可以存储一个或多个键值对。
  2. threshold(阈值): 表示数组的容量阈值,当存储的键值对数量超过阈值时,会触发扩容操作。通常为容量与负载因子的乘积。
  3. loadFactor(负载因子): 表示哈希表的负载因子,用于确定何时进行扩容。负载因子是存储容量与实际键值对数量之间的比率,例如,0.75 表示当存储的键值对数量达到容量的 75% 时,进行扩容。
  4. size(大小): 表示当前存储的键值对数量。
  5. modCount(修改次数): 表示 HashMap 的结构修改次数,用于支持迭代器的快速失败机制。
  6. threshold(阈值): 当数组容量超过此值时,数组将被重新分配。
  7. loadFactor(负载因子): 当存储的键值对数量达到数组容量的负载因子时,进行扩容。

hashmap 的hash算法:

具体来说,JDK 8 中的 HashMap 采用了以下的散列算法:

  1. 获取原始哈希值: 首先,会调用键的 hashCode() 方法获取键的原始哈希值。
  2. 扰动函数(Spread Function): JDK 8 的 HashMap 会使用一个扰动函数(spread function)来对原始哈希值进行处理,以便更好地分散哈希值的分布。这个扰动函数的实现会将原始哈希值进行一些位操作,使得高位的影响能够影响到低位,从而更好地减少哈希冲突。

hashmap的rehash优化:

JDK 1.8 中引入了“树化分裂”机制,它在 rehash 过程中不会一次性地将链表全部转换为红黑树,而是分批次进行。具体来说,当链表长度超过阈值(默认为8)时,会将链表的前 8 个节点直接保留在链表中,而剩余的节点会被放置到新桶中。这样做的目的是为了保持链表的局部性,减少树化过程中的性能开销。

这个“树化分裂”的机制在 resize 方法中得到应用,当进行 rehash 时,会对链表进行分裂,一部分节点继续保留在链表中,而另一部分节点则被放置到新桶中的树中。