快来,我悄悄的给你说几个HashCode的破事。 (1)

简介: 快来,我悄悄的给你说几个HashCode的破事。 (1)

Hash冲突是怎么回事


在这个文章正式开始之前,先几句话把这个问题说清楚了:我们常说的 Hash 冲突到底是怎么回事?


直接上个图片:


image.png


你说你看到这个图片的时候想到了什么东西?


有没有想到 HashMap 的数组加链表的结构?


对咯,我这里就是以 HashMap 为切入点,给大家讲一下 Hash 冲突。


接着我们看下面这张图:


image.png


假设现在我们有个值为 [why技术] 的 key,经过 Hash 算法后,计算出值为 1,那么含义就是这个值应该放到数组下标为 1 的地方。


但是如图所示,下标为 1 的地方已经挂了一个 eat 的值了。这个坑位已经被人占着了。


那么此时此刻,我们就把这种现象叫为 Hash 冲突。


HashMap 是怎么解决 Hash 冲突的呢?


链地址法,也叫做拉链法。


数组中出现 Hash 冲突了,这个时候链表的数据结构就派上用场了。


链表怎么用的呢?看图:


image.png


这样问题就被我们解决了。


其实 hash 冲突也就是这么一回事:不同的对象经过同一个 Hash 算法后得到了一样的 HashCode。


那么写到这里的时候我突然想到了一个面试题:


请问我上面的图是基于 JDK 什么版本的 HashMap 画的图?


为什么想到了这个面试题呢?


因为我画图的时候犹豫了大概 0.3 秒,往链表上挂的时候,我到底是使用头插法还是尾插法呢?


image.png


众所周知,JDK 7 中的 HashMap 是采用头插法的,即 [why技术] 在 [eat] 之前,JDK 8 中的 HashMap 采用的是尾插法。


这面试题怎么说呢,真的无聊。但是能怎么办呢,八股文该背还是得背。


面试嘛,背一背,不寒碜。


构建 HashCode 一样的 String


前面我们知道了,Hash 冲突的根本原因是不同的对象经过同一个 Hash 算法后得到了一样的 HashCode。


这句话乍一听:嗯,很有道理,就是这么一回事,没有问题。


比如我们常用的 HashMap ,绝大部分情况 key 都是 String 类型的。要出现 Hash 冲突,最少需要两个 HashCode 一样的 String 类。


那么我问你:怎么才能快速弄两个 HashCode 一样的 String 呢?


image.png


怎么样,有点懵逼了吧?


从很有道理,到有点懵逼只需要一个问题。


来,我带你分析一波。


我先问你:长度为 1 的两个不一样的 String,比如下面这样的代码,会不会有一样的 HashCode?


String a = "a";
String b = "b";


肯定是不会的,对吧。


如果你不知道的话,建议你去 ASCII 码里面找答案。


我们接着往下梳理,看看长度为 2 的 String 会不会出现一样的 HashCode?


要回答这个问题,我们要先看看 String 的 hashCode 计算方法,我这里以 JDK 8 为例:


image.png


我们假设这两个长度为 2 的 String,分别是 xy 和 ab 吧。


注意这里的 xy 和 ab 都是占位符,不是字符串。


类似于小学课本中一元二次方程中的未知数 x 和 y,我们需要带入到上面的 hashCode 方法中去计算。


hashCode 算法,最主要的就是其中的这个 for 循环。


image.png


h 初始情况下等于 0。


String 类型的底层结构是 char 数组,这个应该知道吧。


所以,value.length 是字符串的长度。val[] 就是这个 char 数组。


把 xy 带入到 for 循环中,这个 for 循环会循环 2 次。


第一次循环:h=0,val[0]=x,所以 h=31*0+x,即 h=x。


第二次循环:h=x,val[1]=y,所以 h=31*x+y。


所以,经过计算后, xy 的 hashCode 为 31*x+y。


同理可得,ab 的 hashCode 为 31*a+b。


由于我们想要构建 hashCode 一样的字符串,所以可以得到等式:


31x+y=31a+b


那么问题就来了:请问 x,y,a,b 分别是多少?


你算的出来吗?


你算的出来个锤子!黑板上的排列组合你不是舍不得解开,你就是解不开。


但是我可以解开,带大家看看这个题怎么搞。


数学课开始了。注意,我要变形了。


image.png

目录
相关文章
|
存储 SQL 大数据
带你读《Apache Doris 案例集》—— 01 招商信诺人寿 基于 Apache Doris 统一 OLAP 技术栈实践(1)
带你读《Apache Doris 案例集》—— 01 招商信诺人寿 基于 Apache Doris 统一 OLAP 技术栈实践(1)
337 0
|
存储 安全 Java
每日大厂面试题大汇总 —— 今日的是“美团-后端开发-一面”
文章汇总了美团后端开发一面的面试题目,内容涉及哈希表、HashMap、二叉树遍历、数据库索引、死锁、事务隔离级别、Java对象相等性、多态、线程池拒绝策略、CAS、设计模式、Spring事务传播机制及RPC序列化工具等。
277 0
|
数据库
mongo占用内存过大解决方案
自己有一个测试用的服务器,配置很低。年前出现几次问题,重启后就好了也就没注意。后来越来越频繁就调查了一下,发现重启后内存就一直增长直到接近100%。使用ps aux查看cpu和内存使用情况,发现mongo占用了大部分的内存,这是什么情况?
900 0
|
Linux Python
如何在服务器上跑python程序
购买服务器 首先你需要一个服务器,阿里云云翼计划有一个9.9云服务器ECS服务。你怎么买我不管,反正你最后给我搞到一个云服务器。 购买的配置界面 由于阿里云现在限量购买,所以这里只是截个图说明而已,主要说明一点公共镜像选择ubuntu14.04 64位,还有root密码别忘了。
11236 1
|
11月前
|
数据采集 JavaScript 前端开发
Python爬虫能处理动态加载的内容吗?
Python爬虫可处理动态加载内容,主要方法包括:使用Selenium模拟浏览器行为;分析网络请求,直接请求API获取数据;利用Pyppeteer控制无头Chrome。这些方法各有优势,适用于不同场景。
|
机器学习/深度学习 数据采集 存储
【机器学习】数据清洗之识别重复点
【机器学习】数据清洗之识别重复点
537 1
|
存储 算法 Java
【DFS(深度优先搜索)详解】看这一篇就够啦
本文介绍了深度优先搜索(DFS)算法及其应用。DFS从某个顶点出发,深入探索图的每条路径,直到无法前进为止,然后回溯。文章详细解释了DFS的基本思想,并通过示例图展示了其执行过程。此外,文中还探讨了三种枚举方式:指数型枚举、排列型枚举和组合型枚举,并提供了具体的代码实现。最后,文章通过几道练习题帮助读者更好地理解和应用DFS算法。
9317 19
【DFS(深度优先搜索)详解】看这一篇就够啦
|
Linux 异构计算
HMI-66-【MeterDisplay for Arm Linux】液晶仪表Arm Linxu迁移
先说结论,虽然移植成功,但是显示效果不理想,可以直接看和面的视频。先说说做了什么吧。
HMI-66-【MeterDisplay for Arm Linux】液晶仪表Arm Linxu迁移
|
Linux 网络架构
通过route , tracert , traceroute 查看本地路由配置及访问ip或域名时经过的路由信息
通过route , tracert , traceroute 查看本地路由配置及访问ip或域名时经过的路由信息
3091 2
|
云计算
阿里云短信验证码平台服务收费价格表
阿里云短信验证码平台服务收费价格表,阿里云短信服务价格表,阿里云短信0.032元一条,阿里云短信价格?阿里云短信怎么收费?阿里云短信多少钱一条,阿里云短信价格0.032元一条
977 0