HashMap中确定数组位置为什么要用hash进行扰动
HashMap数据存储的过程先根据key获得hash值,通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。
其中,jdk1.8中扰动函数hash的源码:
static final int hash(Object key) {
int h;
// key.hashCode():返回散列值也就是hashcode
// ^ :按位异或
// >>>:无符号右移,忽略符号位,空位都以0补齐
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
其中看到在获得hash值时将key的hashCode异或上其无符号右移16位,Hashmap这么做原因:
防止一些实现比较差的 hashCode() 方法,使用扰动函数之后可以减少碰撞,进一步降低hash冲突的几率。
打个比方, 当我们的数组长度n为16的时候,哈希码(字符串“abcabcabcabcabc”的key对应的哈希码)对(16-1)与操作,对于多个key生成的hashCode,只要哈希码的后4位为0,不论不论高位怎么变化,最终的结果均为0。 如下图所示:
| 1954974080(HashCode) | 111 0100 1000 0110 1000 1001 1000 0000 |
| 2^4-1=15(length-1) | 000 0000 0000 0000 0000 0000 0000 1111 |
| &运算 | 000 0000 0000 0000 0000 0000 0000 0000 |
而加上高16位异或低16位的“扰动函数”后,结果如下:
| 原HashCode | 1954974080 | 111 0100 1000 0110 1000 1001 1000 0000 |
| (>>>16)无符号右移16位 | 29830 | 000 0000 0000 0000 0111 0100 1000 0110 |
| ^(异或)运算 | 1955003654 | 111 0100 1000 0110 1111 1101 0000 0110 |
| 2^4-1=15(length-1) | 15 | 000 0000 0000 0000 0000 0000 0000 1111 |
| &(与)运算 | 6 | 000 0000 0000 0000 0000 0000 0000 0110 |
可以看到: 扰动函数优化前:1954974080 % 16 = 1954974080 & (16 - 1) = 0 扰动函数优化后:1955003654 % 16 = 1955003654 & (16 - 1) = 6 很显然,减少了碰撞的几率。
参考:https://zhuanlan.zhihu.com/p/76735726
HashMap中确定数组位置为什么要用hash进行扰动的更多相关文章
- JS查找数组中出现的位置及个数
查找某个值在数组中出现的位置 var attr = [1,4,5,3,2,7,6,9]; var zhao = 8; var sy = -1; for(var i=0;i<attr.length ...
- MongoDB 学习笔记之 从数组中删除元素和指定数组位置
从数组中删除元素: 从数组中删除单个元素: db.ArrayTest.updateOne({ "name" : "Bill"},{$pop: {"ad ...
- 如果两个对象具有相同的哈希码,但是不相等的,它们可以在HashMap中同时存在吗?
如果两个对象具有相同的哈希码,但是不相等的,它们可以在HashMap中同时存在吗? ----答案是 可以 原因: 在hashmap中,由于key是不可以重复的,他在判断key是不是重复的时候就判断了h ...
- JDK1.8 HashMap中put源码分析
一.存储结构 在JDK1.8之前,HashMap采用桶+链表实现,本质就是采用数组+单向链表组合型的数据结构.它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置.Hash ...
- HashMap中的散列函数、冲突解决机制和rehash
一.概述 散列算法有两个主要的实现方式:开散列和闭散列,HashMap采用开散列实现. HashMap中,键值对(key-value)在内部是以Entry(HashMap中的静态内部类)实例的方式存储 ...
- HashMap中的resize以及死链的情况
之前我已经写过关于HashMap的内容了:http://www.cnblogs.com/wang-meng/p/7545725.html 我们都知道HashMap是线程不安全的, 如果多线程来访问会有 ...
- 关于hashMap中 计算hashCode的逻辑推理(二)
hashMap中,为了使元素在数组中尽量均匀的分布,所以使用取模的算法来决定元素的位置.如下: //方法一: static final int hash(Object key){//jdk1.8 in ...
- HashMap中的hash算法总结
前言 算法一直是我的弱项,然而面试中基本是必考的项目,刚好上次看到一个HashMap的面试题,今天也来学习下 HashMap中的hash算法是如何实现的. 数学知识回顾 << : 左移运算 ...
- hashCode及HashMap中的hash()函数
一.hashcode是什么 要理解hashcode首先要理解hash表这个概念 1. 哈希表 hash表也称散列表(Hash table),是根据关键码值(Key value)而直接进行访问的数据结构 ...
随机推荐
- Node.js之querystring模块
querystring从字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析.querystring模块只提供4个方法,在我看来,这4个方法是相对应的. 这4个方法分别是querystr ...
- Git远程新建分支之后,本地看不到最新分支
git remote update origin –prune 注意 双- csdn 对于 两个 - 看起来像一个
- 如何用 Redis 统计独立用户访问量
众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作3年的开发,稍微优秀一点的,都给到30K的Offer,当然,拼多多加班也是出名的,一周上6天班是常态,每天工作时间基本都是超过1 ...
- linux操作目录命令之mkdir与rmdir
一.mkdir 创建目录(一个或多个目录) mkdir -m 777 -p path 1)-m 对新建目录设置权限 2)-p 可以是一个路径名称.此时若路径的某一级目录尚不存在,使有该选项后系统 ...
- [Usaco2010 Dec]Treasure Chest 藏宝箱
题目链接:点这里 Solution: 刚开始以为是博弈论,然而不是... 首先考虑n方dp,设f(l,r)为只有\(l\)到\(r\)区间的钱的先手最大获利 那么我们可以得到式子f(l,r)=sum( ...
- sh_04_第1个函数改造
sh_04_第1个函数改造 name = "小明" # say_hello() # Python 解释器知道下方定义了一个函数 def say_hello(): "&qu ...
- 花式求LCA
设树上有两点x.y,要求他们的lca(最近公共祖先) 1.倍增求LCA: 先预处理出树上每个点的向上2^k的祖先. 再看x.y:先把深度深的倍增跳到和深度浅的一样的深度,判断是否在同一点:是,该点即为 ...
- 简单记录一下vue生命周期及 父组件和子组件生命周期钩子执行顺序
首先,vue生命周期可以用下图来简单理解 当然这也是官方文档的图片,详细的vue周期详解请参考这里 然而当同时存在父子组件的时候生命周期钩子是如何执行的呢? 请看下文: 加载渲染过程父beforeCr ...
- splice()、slice()、split()函数的区分
1.slice(数组) 用法:array.slice(start,end) 解释:该方法是对数组进行部分截取,并返回一个数组副本:参数start是截取的开始数组索引,end参数等于你要取的最后一个字符 ...
- 记一次全局分区索引update调优
原始SQL: CREATE OR REPLACE PROCEDURE sp_upd_suppressed_emails( A_LIMIT_BULK IN PLS_INTEGER DEFAULT 20 ...