hashmap存储方式 hash碰撞及其解决方式

news2025/1/11 17:54:01
1.Map 的存储特点
Map 这个结构中,数据是以键值对(key-value)的形式进行存储的,每一个存储进 map 的数据都是一一对应的。
创建一个 Map 结构可以使用 new HashMap() 以及 new TreeMap() 两种方式,两者之间的区别是: TreeMap 是支持 排序的。
2.HashMap 的底层存储方式

 

总结 :
1. hashMap 存储数据 (key,value) 的时候使用 put 方法
2. put 方法会调用 putVal 方法 , hash(hey) 和当前的 key value 作为参数传进来
3. 判断数组是否为空,即判断是否是第一次添加数据 , 如果是的话,会先调用 resize 方法扩容
4. 之后 , 根据当前 key hash 值找到它在数组中的下标 ( 怎么算的 ? index = (n - 1) & hash) ,判断当前下标位置是 否已经存在元素
5. 如果不存在,直接把 key value 包装成 Node 节点作为链表头存入数组
6. 如果存在,分为三种情况
1. )比较一下已有数据和存入数据 如果 hash 值等于传过来的 hash ,并且他们的 key 值也相等 最后会把 value的值覆盖处理
2. )上一步不相等,就判断一下当前是不是红黑树结构,是则调用 putTreeVal() 把它加入到红黑树
3. )既不相等,也不是红黑树结构,说明是普通链表结构,遍历这个链表,将数据存到链表尾部
1. 在遍历过程中,如果是最后一个节点,则插入新节点 newNode(hash, key, value, null)
2. 如果链表长度超过了 8 ,则转化为红黑树 treeifyBin(tab, hash) 3. 如果遍历的时候遇到了相同的 key value 的值覆盖处理
7. 如果当前数组中的元素个数超过阈值,则扩容 resize();
8. putVal ()方法 没修改 value 就返回 NULL 修改了就返回旧值(之前的 value
3. 什么是 hash 碰撞
Hash Collision 就是我们说的 Hash 碰撞或者 Hash 冲突。
这个其实也非常好理解,就是 2 个输入不同的数据,经过 Hash 算法后,得到的 Hash 值是一样的。
HashMap 的查询和添加过程中,绕不过去的是计算元素在数组的位置 index key HashCode 作为这个计算的 基础。计算后的Hash 值存在相同的情况, hash 与长度取余的结果也有相同的情况,这个时候运算结果相同的两个 对象就需要存储到同一个链表中,这就是HashMap 中的 Hash 碰撞。
4. 如何解决 hash 碰撞
1. 开放地址方法
1 )线性探测
按顺序决定值时,如果某数据的值已经存在,则在原来值的基础上往后加一个单位,直至不发生哈希冲突。 就是在
此空间不足时,直接放入此空间的后一个空的空间
2 )再平方探测
按顺序决定值时,如果某数据的值已经存在,则在原来值的基础上先加 1 的平方个单位,若仍然存在则减 1 的平方个
单位。随之是 2 的平方, 3 的平方等等。直至不发生哈希冲突。 要注意平方不能超过容量的值 Size=16 的时候,找备
选的单元只能取 i=1,2,3 ,也就是距离冲突单元 1,4,9 个单位的位置了。
3 )伪随机探测
按顺序决定值时,如果某数据已经存在,通过随机函数随机生成一个数,在原来值的基础上加上随机数,直至不发
生哈希冲突。
2. 链式地址法( HashMap 的哈希冲突解决方法)
对于相同的值,使用链表进行连接。使用数组存储每一个链表。 就是 hashmap 的底层原理 :数组 + 链表 就是没有
红黑树
补充:在 JDK1.8 HashMap 通过链式寻址法以其红黑树来解决哈希冲突的,其中红黑树是为了优化哈希表的链表
过长 导致遍历时间复杂度增加的问题。当链表长度大于 8 并且哈希表的容量大于 64, 再向链表中添加元素 , 会转化为
红黑树。 优点:
1 )拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较
2
由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况; (
3 )开放定址法为
减少冲突,要求装填因子 α 较小,故当结点规模较大时会浪费很多空间。而拉链法中可取 α≥ 1 ,且结点较大时,拉 链法中增加的指针域可忽略不计,因此节省空间; (
4 )在用拉链法构造的散列表中,删除结点的操作易于实现。
只要简单地删去链表上相应的结点即可。 缺点:
1 ) 指针占用较大空间时,会造成空间浪费,若空间用于增大散列表规模进而提高开放地址法的效率。
3. 建立公共溢出区
建立公共溢出区存储所有哈希冲突的数据
4. 再哈希法
对于冲突的哈希值再次进行哈希处理,直至没有哈希冲突。
5. 如何解决并发
HashMap 的线程不安全主要体现在下面两个方面:
1. JDK1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况。 2. JDK1.8 中,在并发执行 put 操作时会
发生数据覆盖的情况。 1 if((p = tab[i =(n -1)& hash])==null)// 1 、此处线程不安全 —— 用来判定索引位置是否
hash 碰撞,比如两个线程 A B 都在进行 put 操作,并且 hash 函数计算出的插入下标是相同的,当线程 A 执行完第六
行代码后由于时间片耗尽导致被挂起,而线程 B 得到时间片后在该下标处插入了元素,完成了正常的插入,然后线
A 获得时间片,由于之前已经进行了 hash 碰撞的判断,所有此时不会再进行判断,而是直接进行插入,这就导致 了线程B 插入的数据被线程 A 覆盖了,从而线程不安全。
2 if (++size > threshold) 中的 ++size :同样还是线程 A B ,这两个线程同时进行 put 操作时,假设当前 HashMap
zise 大小为 10 ,当线程 A 执行到此行代码时,从主内存中获得 size 的值为 10 后准备进行 +1 操作,但是由于时间片
耗尽只好让出 CPU ,线程 B 快乐的拿到 CPU 还是从主内存中拿到 size 的值 10 进行 +1 操作,完成了 put 操作并将
size=11 写回主内存,然后线程 A 再次拿到 CPU 并继续执行 ( 此时 size 的值仍为 10) ,当执行完 put 操作后,还是将
size=11 写回内存,此时线程 A B 都执行了一次 put 操作,但是 size 的值只增加了 1 ,所有说还是由于数据覆盖又导
致了线程不安全。
解决方法: 1.Hashtable
HashTable 为了实现多线程安全,在几乎所有的方法上都加上了 synchronized 锁(锁的是类的实例 , 也就是整个
map 结构),当一个线程访 问 Hashtable 的同步方法时,其他线程如果也要访问同步方法,会被阻塞住。
2.Collections.synchronizedMap( 一般不用 ) 缺点 : 从锁的角度来看,基本上是锁住了尽可能大的代码块 . 性能会比较
3.ConcurrentHashMap (常用) JDK 1.7 中,采用分段锁的机制,实现并发的更新操作,底层采用数组 + 链表的 存储结构,包括两个核心静态内部类 Segment HashEntry 。 ①、 Segment 继承 ReentrantLock (重入锁) 用
来充当锁的角色,每个 Segment 对象守护每个散列映射表的若干个桶; ②、 HashEntry 用来封装映射表的键 - 值 对; ③、每个桶是由若干个 HashEntry 对象链接起来的链表 分段锁: Segment 数组中,一个 Segment 对象就是一 把锁, 对应一个 HashEntry 数组 , 该数组中的数据同步依赖于同一把锁 , 不同 HashEntry 数组的读写互不干扰
JDK 1.8 中抛弃了原有的 Segment 分段锁,来保证采用 Node + CAS + Synchronized 来保证并发安全性。取消类 Segment,直接用 table 数组存储键值对;当 Node 对象组成的链表长度超过 TREEIFY_THRESHOLD 时,链表转换
为红黑树,提升性能。底层变更为数组 + 链表 + 红黑树。 CAS 性能很高,但 synchronized 之前一直都是重量级的 锁,jdk1.8 引入了 synchronized ,采用锁升级的方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/403138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TVS和稳压管的相同点和不同点

大家好,我是记得诚。 文章目录 介绍相同点不同点介绍 TVS和稳压管都是电路中很常用的电子元器件,都是二极管的一个种类。 TVS二极管全称是Transient voltage suppression diode,也叫瞬态电压抑制二极管。 稳压二极管英文名字Zener diode,又叫齐纳二极管。 关于稳压二极…

Jenkins从下载到部署项目的流程

Jenkins安装配置1.1 Jenkins介绍Jenkins 是一款流行的开源持续集成(Continuous Integration)工具,广泛用于项目开发,具有自动化构建、测试和部署等功能。官网: http://jenkins-ci.org/。Jenkins的特征:开源…

谷粒学院开发(三):统一日志、异常及前端准备工作

特定异常处理 ControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class) // 指定出现什么异常会被处理ResponseBody // 为了能够返回数据public R error(Exception e) {e.printStackTrace();return R.error().message("执行了全局异常…

Linux--磁盘存储管理 分区工具 fdisk 分区实操 详解~

上一篇文章介绍了 fdisk 的各个菜单功能,这篇,我们直接实操 管理磁盘 fdisk :分区 : 我们上一篇文章里讲过,上篇文章的 磁盘 /dev/nvme0n1 空间已经满了因此 , 又重新添加了一块儿硬盘~!!>&g…

传统图像处理之颜色特征

博主简介 博主是一名大二学生,主攻人工智能研究。感谢让我们在CSDN相遇,博主致力于在这里分享关于人工智能,c,Python,爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主,博主会继续更新的&#xff0c…

UML时序图速查——架构设计必备技能

目录 一、时序图概述 二、时序图元素 1. Actor(角色)& Object(对象) 2. Lifeline(生命线) 3. Message(消息) 4. Combined Fragment(组合片段) 5. …

【Linux】多线程---线程控制

进程在前面已经讲过了,所以这次我们来讨论一下多线程。前言:线程的背景进程是Linux中资源及事物管理的基本单位,是系统进行资源分配和调度的一个独立单位。但是实现进程间通信需要借助操作系统中专门的通信机制,但是只这些机制将占…

java并发入门(一)共享模型—Synchronized、Wait/Notify、pack/unpack

一、共享模型—管程 1、共享存在的问题 1.1 共享变量案例 package com.yyds.juc.monitor;import lombok.extern.slf4j.Slf4j;Slf4j(topic "c.MTest1") public class MTest1 {static int counter 0;public static void main(String[] args) throws InterruptedEx…

如何科学管理技术团队的研发交付速率?

每当提及「研发效能」,我们都在谈论什么? 研发效能管理要在保证质量的前提下,思考如何更快地向客户交付价值。在管理实践中,效能度量涉及三大维度:交付速率、交付质量、交付价值。 技术团队对内如何优化开发流程&…

STM32实战项目-基本定时器

前言: 通过基本定时器TIM6,让三个LED灯每间隔1s闪烁一次。 目录 1.基本定时器参数配置 1.1框图分析 1.2参数配置 2.软件程序 2.1整体框架 2.2定时器结构体 2.3定时器回调函数 1.基本定时器参数配置 1.1框图分析 TIM6作为基本定时器 它是挂载…

【Linux】-- 线程池

目录 铺垫 内存 线程的角度 线程池 基本代码结构 对于线程池的生产消费的完善 初步实现线程池生产消费 结合日志完善线程池 铺垫 内存 (以STL处理方式,引入提供效率的一种思想) 通过进行C语言与C语言的学习中,平时我们使…

C语言 深度剖析数据在内存中的存储(2)

本次博客是继上次博客,继续向下剖析数据在内存当中的存储。练习浮点型在内存中的存储练习代码1:int main() {char a -1;signed char b-1;unsigned char c-1;printf("a%d,b%d,c%d",a,b,c);return 0; }1.在本题中首先我们要知道的是%d打印的是有…

【数据结构之树】——什么是树,树的特点,树的相关概念和表示方法以及在实际的应用。

文章目录一、1.树是什么?2.树的特点二、树的相关概念三、树的表示方法1.常规方法表示树2.使用左孩子右兄弟表示法3. 使用顺序表来存储父亲节点的下标三、树在实际的应用总结一、1.树是什么? 树是一种非线性的数据结构,它是由n(n&…

MatCap模拟光照效果实现

大家好,我是阿赵 之前介绍过各种光照模型的实现方法。那些光照模型的实现虽然有算法上的不同,但基本上都是灯光方向和法线方向的计算得出的明暗结果。 下面介绍一种叫做MatCap的模拟光照效果,这种方式计算非常简单,脱离灯光的计算…

javaWeb核心05-FilterListenerAjax(Axios)json

文章目录Filter&Listener&Ajax1,Filter1.1 Filter概述1.2 Filter快速入门1.2.1 开发步骤1.2.2 代码演示1.3 Filter执行流程1.4 Filter拦截路径配置1.5 过滤器链1.5.1 概述1.5.2 代码演示1.5.3 问题1.6 案例1.6.1 需求1.6.2 分析1.6.3 代码实现1.6.3.1 创建F…

Linux 安装 nginx 详细教程

文章目录Linux 安装 nginx 详细步骤①安装依赖包②下载并解压安装包③安装 nginx④启动 nginx 服务⑤配置 nginx.conf提示:以下是本篇文章正文内容,Linux 系列学习将会持续更新 Linux 安装 nginx 详细步骤 ①安装依赖包 下载模块依赖性 Nginx 需要依赖…

resp无法连接Redis服务的解决方法

在保证Windows主机和Linux虚拟机能够相互ping通的前提下,resp仍无法连接到Linux上的redis服务,那么需要考虑以下原因: Linux防火墙问题,Linux未关闭防火墙,或防火墙未放通6379/tcp端口;redis配置问题&#…

Project ERROR: Unknown module(s) in QT: webenginewidgets

Qt系列文章目录 文章目录Qt系列文章目录前言一、问题定位二、解决方法1.引入WebEngine库2.重新打开工程3. 解决办法:运行结果前言 最近项目中需要用到:Qt中使用cesium三维引擎库,涉及到Qt和和JavaScript之间通信,工程源码报错&am…

202109-3 CCF 脉冲神经网络 66分题解 + 解题思路 + 解题过程

解题思路 根据题意&#xff0c;脉冲源的阈值大于随机数时&#xff0c;会向其所有出点发送脉冲 神经元当v>30时&#xff0c;会向其所有出点发送脉冲&#xff0c;unordered_map <int, vector > ne; //存储神经元/脉冲源的所有出点集合vector 所有脉冲会有一定的延迟&am…

opencv-图像操作

访问和修改像素值 我们先加载一个彩色图像&#xff1a; import cv2img cv2.imread(b.png) print(img)########### 打印结果 ########### [[[243 243 243][243 243 243][243 243 243]...[243 243 243][243 243 243][243 243 243]][[243 243 243][243 243 243][243 243 243].…