图解HashMap和HashSet的内部工作机制

转载自 图解HashMap和HashSet的内部工作机制

HashMap 和 HashSet 内部是如何工作的?散列函数(hashing function)是什么?

HashMap 不仅是一个常用的数据结构,在面试中也是热门话题。

Q1. HashMap 如何存储数据?
A1. 以键/值对(key/value)形式存储。你可以使用键(key)来存、取值。

Q2. HashMap 查询时间的复杂度是怎样的?
A2. 是O(n) = O(k * n)。如果 hashCode() 方法能向下面讨论的那样把数据分散到桶(bucket)中,那么平均是O(1)。

Q3. HashMap 内部是如何存储数据的?
A3. HashMap 使用后台数组(backing array)作为桶,并使用链表(linked list)存储键/值对。

桶的后台数组:如下所示


1)使用键(key)和值(value)将一个对象放入 map 中时,会隐式调用 hashCode() 方法,返回哈希值(hash code value),比如 123。两个不同的键能够返回一样的哈希值。良好的哈希算法(hashing algorithm)能够将数值分散开。在上面的例子中,我们假设 (“John”,01/01/1956) 的键和 (“Peter”, 01/01/1995) 的键返回相同的哈希值,都是 123


2)当返回一个 hashCode,例如是 123,初始的 HashMap 容量为 10,它如何知道存储到后台数组(backing array)的哪个索引(index)呢?HashMap 内部会调用 hash(int ) 和 indexFor(int h, int length) 方法。这被称为哈希函数(hashing function)。
简要解释下这个函数:

1
2
3
4
hashCode() % capacity
123% 10= 3
456% 10= 6

这表示,“hashCode = 123”存储在备份数组的索引3上。
容量为 10 的情况下,你可能得到的数字在 0 到 9 之间。
一旦 HashMap 达到容量的 75%,也就是哈希因子(hash factor)默认值 0.75,后台数组(backing array)的容量就会加倍,发生重散列(rehashing)为新的 20 的容量重新分配桶。

1
2
3
4
hashCode() % capacity
123% 20= 3
456% 20= 16

上面重散列的取模方法有一个缺陷。如果 hashCode 是负数会怎样?负索引可不是你想要的。因此,一个改进的哈希公式会移出符号位,然后再用取模(即 %)运算符计算剩余部分。

1
2
(123 & 0x7FFFFFFF) % 20= 3
(456& 0x7FFFFFFF) % 20= 16

这确保你得到的索引值为正数。如果你查看 Java 8 的 HashMap 源码,它的实现使用以下方法:

a). 通过只抽取重要的低位,来防止不良离散值(poorer hashes)。

1
2
3
4
5
6
7
staticint hash(inth) {
     // This function ensures that hashCodes that differ only by
     // constant multiples at each bit position have a bounded
     // number of collisions (approximately 8 at default load factor).
     h ^= (h >>> 20) ^ (h >>> 12);
     returnh ^ (h >>> 7) ^ (h >>> 4);
}

b). 根据哈希码hashCode)和容量capacity),来决定索引(index)。

1
2
3
staticint indexFor(inth, intlength) {
     returnh & (length-1);
}

实际的名称值对(name value pairs)作为一个键/值对存储在 LinkedList 中。

如上图所示,键/值对以链表形式存储。两个不同的键可以产生一样的 hashCode,例如123,并存储在同一个 bucket 中,理解这点至关重要。例如,上面例子中的 “John, 01/01/1956” 和 “Peter, 01/01/1995“ 。你如何只检索 “John, 01/01/1956” 呢?此时你的 key 所属类的 equals() 方法会被调用。它遍历 bucket 为 “123” 的 LinkedList 中的每个条目,使用 equals() 方法找到并检索出键为 “John, 01/01/1956” 的条目。这就是在你的类中实现 hashCode() 和 equals() 方法重要性的原因。如果你使用一个现有的包装类,如 Integer 或 String 作为键,它们已经实现了这两个方法。如果你使用自己写的类作为键,如 “John, 01/01/1956” 这样含有名字和出生日期属性的“MyKey”,你有责任正确地实现这些方法。

Q5. 为什么恰当地设置 HashMap 的初始容量(initial capacity)是最佳实践?
A5. 这样可以减少重散列的发生。

Q6. HashSet 内部如何存储数据?
A6. HashSet 内部使用 HashMap 。它将元素存储为键和值。(译者注:HashSet 把存储的值作为 key)

Q7. 为 Object 实现了一个糟糕的 hashcode() 会有什么影响?
A7. 不同的对象调用 hashCode() 方法应该返回不同的值。如果不同的对象返回相同的值,会导致更多的键/值对存储在同一个 bucket 中。这会降低 HashMap 和 HashSet 的性能

原文链接:  Arulkumaran Kumaraswamipillai  翻译:  ImportNew.com  齐帜背单词吧
译文链接:  http://www.importnew.com/21841.html

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

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

相关文章

window location href 手机端无法跳转_Window对象在前端领域的角色

特殊的window提起window,在网页当中很常见,比如像这样:window.onloadfunction(){ //执行函数体 }这段代码的意思是当网页内容加载完成后要做什么。在js的领域,window对象有着双重角色,既是用来访问浏览器窗口的接口&am…

leetcode初级算法2.旋转数组

leecode初级算法2.旋转数组 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我自己的解法&#xff1a; public static void rotate(int[] nums, int k) {int move k % nums.length;Stack<Integer> stack new Stack<>();if(move 0){return;}else {f…

java运行环境变量及自定义变量

【README】 本文主要介绍java运行环境变量的获取&#xff0c;如何读取 env.properties 文件并将自定义变量写入到系统变量&#xff1b; 【1】System.getenv() 获取环境变量 public static void main1() {Map<String, String> envMap System.getenv();envMap.entrySet(…

Java HashSet和HashMap源码剖析

转载自 Java HashSet和HashMap源码剖析总体介绍 之所以把HashSet和HashMap放在一起讲解&#xff0c;是因为二者在Java里有着相同的实现&#xff0c;前者仅仅是对后者做了一层包装&#xff0c;也就是说HashSet里面有一个HashMap&#xff08;适配器模式&#xff09;。因此本文将重…

怎么把页面按比例缩小_meta viewport 是做什么用的,怎么写?

前置知识&#xff08;有助于viewport的理解&#xff09;李明&#xff1a;设备像素、设备独立像素、CSS像素、分辨率、PPI、devicePixelRatio​zhuanlan.zhihu.com移动端的问题屏幕窄&#xff0c;一般来说设备独立像素不超过400px。比如把网站侧边栏宽度设置为10%&#xff0c;这…

(转)java动态代理与aop

转自&#xff1a; Java 动态代理与AOP - 如果的事 - 博客园动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy)&#xff0c;并由代理对象控制对target对象的引用。 模式图&#xff1a; 代理模式中的角色有&#xff1a; 抽象对象角色(Abstrachttps://…

ConcurrentHashMap的红黑树实现分析

转载自 ConcurrentHashMap的红黑树实现分析红黑树 红黑树是一种特殊的二叉树&#xff0c;主要用它存储有序的数据&#xff0c;提供高效的数据检索&#xff0c;时间复杂度为O(lgn)&#xff0c;每个节点都有一个标识位表示颜色&#xff0c;红色或黑色&#xff0c;有如下5种特性&a…

leetcode初级算法3.存在重复元素

leetcode初级算法3.存在重复元素 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a; Arrays.sort(nums);for(int i 0; i < nums.length-1; i){if(nums[i] nums[i1]){return true;}}return false;官方题解&#xff1a; public boolean con…

sql server累计求和函数_SQL基础--SQL高级功能

一.窗口函数有什么用&#xff1f;在日常工作中&#xff0c;经常会遇到需要在每组内排名&#xff0c;比如下面的业务需求&#xff1a;排名问题&#xff1a;每个部门按业绩来排名topN问题&#xff1a;找出每个部门排名前N的员工进行奖励面对这类需求&#xff0c;就需要使用sql的高…

(转)【SpringMvc】如何使用form发送PUT和DELETE请求

转自&#xff1a; https://blog.csdn.net/cockroach02/article/details/82194126https://blog.csdn.net/cockroach02/article/details/82194126 一、当前现状 浏览器使用form提交信息的时候只支持GET和POST&#xff0c;如果需要在浏览器上使用PUT和DELETE请求方式的话&#…

leetcode初级算法4.只出现一次的数字

leetcode初级算法4.只出现一次的数字 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a; public static int singleNumber(int[] nums) {if(nums.length 1){return nums[0];}Arrays.sort(nums);int slow 0;int fast 1;while(fast < nums.…

集合总结(Collection)

转载自 集合总结(Collection) 最近项目上线完&#xff0c;闲来无事&#xff0c;整理了关于集合相关对比&#xff0c;具体详见以下几点&#xff1a;1.ArrayList和Vector区别&#xff1a;这两个类都实现了List接口(List接口继承了Collection接口)&#xff0c;他们都是有序集合&am…

springboot接收浏览器发送delete请求( method not allowed 405解决方法)

【README】 浏览器使用form提交信息的时候只支持GET和POST&#xff0c;如果需要在浏览器上使用PUT和DELETE请求方式的话&#xff0c;只能使用欺骗的方式了&#xff0c;SpringMvc提供了HiddenHttpMethodFilter类来提供支持&#xff1b; 【1】前端 1&#xff09;list.html <…

tensorflow图形检测_社交距离检测器——Tensorflow检测模型设计

在隔离期间&#xff0c;我花时间在github上探索Tensorflow的大量预训练模型。这样做时&#xff0c;我偶然发现了一个包含25 个带有性能和速度指标的预训练对象检测模型的存储库。拥有一些计算机视觉知识并给出了实际的背景知识&#xff0c;我认为使用其中之一来构建社交隔离应用…

leetcode初级算法4.两个数组的交集 II

leetcode初级算法4.两个数组的交集 II 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a;&#xff08;总结在代码中&#xff09; public int[] intersect(int[] nums1, int[] nums2) {//为空则返回if(nums1 null || nums2 null){return null;…

Java NIO:Buffer、Channel 和 Selector

转载自 Java NIO&#xff1a;Buffer、Channel 和 Selector本文将介绍 Java NIO 中三大组件 Buffer、Channel、Selector 的使用。 本来要一起介绍非阻塞 IO 和 JDK7 的异步 IO 的&#xff0c;不过因为之前的文章真的太长了&#xff0c;有点影响读者阅读&#xff0c;所以这里将它…

(转)使用IDEA将普通MAVEN项目转为WEB项目

转自&#xff1a; 使用IDEA将普通MAVEN项目转为WEB项目_yun0000000的博客-CSDN博客使用IDEA将普通MAVEN项目转为WEB项目https://blog.csdn.net/yun0000000/article/details/70664944 1、file--project Structure--,然后点“”号&#xff0c;,若没有war包&#xff0c;可修改mav…

python创建文件对象_python基础教程:文件读写

在Linux系统中&#xff0c;一切都是文件。但我们通常说的文件是保存在磁盘上的图片、文档、数据、程序等等。而在程序的IO操作中&#xff0c;很多时候就是从磁盘读写文件。本节我们讲解Python中的文件对象如何操作文件。创建文件对象 通过Python内置函数open()可以很容易的创建…

(转)springboot:添加JSP支持

转自&#xff1a; 14.springboot:添加JSP支持 - 简书&#xff08;1&#xff09;创建Maven web project 使用Eclipse新建一个Maven Web Project &#xff0c;项目取名为&#xff1a;spring-boot-jsp &#xff08;2&#xff09;在pom.xm...https://www.jianshu.com/p/4216bbd1e0…

leetcode初级算法5.加一

leetcode初级算法5.加一 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a;&#xff08;总结在代码中&#xff09; public int[] plusOne(int[] digits) {//获取digits长度int length digits.length;//判断条件int count 0;//全是9的情况for …