什么是Hash以及HashMap

本文深入探讨了哈希算法的基本原理,包括其不可逆性、哈希碰撞及常见的哈希函数。同时,详细分析了Java中HashMap的内部结构、工作原理,以及其在面对数据增长时的扩容策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

哈希总结


总结:
1.哈希又称散列哈希算法也称散列算法

2.哈希一般指哈希算法,即将任意值(如:‘纸上得来终觉浅’)经过hash算法可得到一个固定长度的组合串(字母和数字组成),如下图:MD5与SHA-256为哈希算法中不同的输出标准。

在这里插入图片描述
3.哈希算法是数据查找技术中最经典的算法之一。所以有用哈希算法建立索引值,加快查询速度。

4.哈希算法具有不可逆性

5.哈希存在"哈希碰撞"。假设f是哈希函数,y是哈希结果,x是键值,可得:y = f(x)
哈希碰撞不同的键值(x)有可能获得相同的结果(y), 这就是hash碰撞。但是不同的y值一定对应不同的x值。

6.基于哈希的存储结构有:HashMapHashTable等。


HashMap总结
问题1: HashMap的内部组成结构(属性)是哪些?以及作用?
问题2:HashMap的默认初始容量(桶)大小?
问题3:理解为什么HashMap底层实现是数组+链表的形式?
问题4:rehash是什么?如果禁用resize()会发生什么?
问题5:hashCode()在java中默认使用的哈希函数是什么,或者说Objects.hashCode()用了什么类型的哈希函数?

问1答:主要属性有如图:原图出自
在这里插入图片描述
table:很多文章都有这样的描述:是一个Entry[]数组类型。这是正确的,但HashMap中是使用Node作为table,Node是Entry的实现类。Node熟悉包括:key,value,hash,next(Node)。
size:容量,最大存储大小,也称桶大小。
loadFactor:加载因子,默认0.75。
threshold阈值,用于判断是否需要调整容量。threshold=“size*threshold”,当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍,出现resize(),rehash。

问2答:默认初始容量=16,默认的加载因子=0.75,也就是说默认阈值=12.

问3答:参考该文

问4答:rehash会发生在当需要扩容的时候,会resize()会触发,对应的key的hashCode也会发生变化,这是扩容时必要的损耗。如果人为操作禁用了resize()那么会因为人为因素形成数组链条,这是数组+链表的体现。

问5答:整理出自
经常使用的构造散列函数的方法

5.1. 直接寻址法:取keyword或keyword的某个线性函数值为散列地址。即H(key)=key或H(key) = a•key + b,当中a和b为常数(这样的散列函数叫做自身函数)

5.2. 数字分析法:分析一组数据,比方一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体同样,这种话,出现冲突的几率就会非常大,可是我们发现年月日的后几位表示月份和详细日期的数字区别非常大,假设用后面的数字来构成散列地址,则冲突的几率会明显减少。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。

5.3. 平方取中法:取keyword平方后的中间几位作为散列地址。

5.4. 折叠法:将keyword切割成位数同样的几部分,最后一部分位数能够不同,然后取这几部分的叠加和(去除进位)作为散列地址。

5.5. 随机数法:选择一随机函数,取keyword的随机值作为散列地址,通经常使用于keyword长度不同的场合。

5.6. 除留余数法:取keyword被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅能够对keyword直接取模,也可在折叠、平方取中等运算之后取模。对p的选择非常重要,一般取素数或m,若p选的不好,easy产生同义词。

JAVA中的Objects.hashCode()默认是使用了5.6除留余数法。所以hashMap的会与容量有关参考出自

参考:

https://www.jianshu.com/p/28cc0f676488

https://blog.youkuaiyun.com/qq_34858648/article/details/79545622

https://www.cnblogs.com/acm-bingzi/p/hash.html

https://www.cnblogs.com/skywang12345/p/3310835.html

https://www.cnblogs.com/peizhe123/p/5790252.html

http://www.cnblogs.com/mengfanrong/p/4034950.html

https://blog.youkuaiyun.com/qq876551724/article/details/78814457

<think>好的,我现在需要回答用户关于HashMap和散列(hashing)的关系及用法的问题。首先,我得回忆一下HashMap的基本概念和散列在其中的作用。根据用户提供的引用内容,特别是引用[1]提到,散列是通过键生成索引来存储和检索值的技术。而引用[2]和[3]讨论了负载因子和Java中HashMap的具体实现差异,比如JDK1.7和1.8的结构变化。 用户的问题是如何在编程中HashMap使用散列。我需要先解释HashMap的基本结构,它如何利用哈希函数将键转换为数组的索引,处理冲突的方法,比如链表或红黑树。然后,要提到负载因子和扩容机制,这些都散列效率密切相关。此外,需要结合引用中的内容,比如负载因子过高会导致性能下降,而好的哈希函数能减少冲突。 接下来,要确保按照系统级指令,正确使用行内公式,比如哈希函数的例子用$h(key)$,可能需要提到哈希码的计算,例如使用$h(key) = key \% capacity$这样的公式。同时,独立公式如果需要的话,用$$包围,并单独成段。但在这个问题中,可能不需要复杂的数学公式,重点在于解释过程。 还需要注意使用中文回答,结构清晰,分步骤说明。最后生成相关问题,比如关于冲突解决、性能优化或不同语言中的实现差异。同时,引用标记要自然地添加在引用的内容末尾,比如引用[1]、[2]、[3]对应的内容。 现在,我需要组织这些信息,确保逻辑连贯,覆盖HashMap如何利用散列技术,包括哈希函数的作用、处理冲突的方法、负载因子的影响,以及具体实现的例子,如Java中的HashMap。可能还需要对比不同版本的实现差异,如JDK1.7和1.8,说明红黑树如何优化性能。最后,生成相关问题,帮助用户进一步探索。</think>### HashMap散列技术的关系及实现原理 HashMap是基于散列表实现的键值对存储结构,其核心逻辑依赖**哈希函数**将键(key)映射到存储桶(bucket)的索引位置[^1]。具体实现分为以下关键步骤: --- #### 1. 哈希函数的核心作用 - **键到索引的转换**:哈希函数$h(key)$将任意类型键转换为固定范围的整数。例如,Java中`Object.hashCode()`生成初始哈希值,再通过模运算确定存储位置: $$h(key) = \text{hashCode}(key) \% \text{capacity}$$ - **减少冲突**:优秀哈希函数需确保键的均匀分布,避免不同键映射到同一索引(即哈希冲突)[^2]。 --- #### 2. 哈希冲突的解决方案 - **链地址法(Separate Chaining)**:每个存储桶维护一个链表(JDK1.7)或红黑树(JDK1.8+),冲突元素追加到同一桶的链表/树中[^3]。 ```java // JDK1.8的节点结构(链表或树节点) static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; // 链表指针 } ``` - **开放寻址法**:其他实现(如Python字典)可能在相邻位置探测空闲桶。 --- #### 3. 负载因子动态扩容 - **负载因子(Load Factor)**:阈值(默认0.75)触发扩容,公式为: $$\text{扩容条件:}\ \frac{\text{元素数量}}{\text{桶数量}} \geq \text{负载因子}$$ 例如,初始容量16的HashMap在存入第12个元素时触发扩容($16 \times 0.75 = 12$)[^2]。 - **扩容优化**:JDK1.8通过高位异或运算减少重新哈希的计算量。 --- #### 4. 实际应用场景 - **高速查询**:基于$O(1)$平均时间复杂度,适用于缓存系统(如Redis)。 - **键值关联存储**:配置管理、数据库索引优化。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值