首页 Java java教程 java中关于散列表的详细介绍

java中关于散列表的详细介绍

Nov 29, 2019 pm 04:23 PM
java 散列表

java中关于散列表的详细介绍

什么是散列表

散列表,也叫作哈希表(Hash Table),是一种提供键(Key)和值(Value)的映射关系的数据结构,只要给出一个Key,就可以高效查找到它所匹配的Value,时间复杂度接近于O(1)。

e419b45d76fbab9af429bb1a2369216.png

在线学习视频推荐:java视频

散列表的工作原理

散列表在本质上是一个数组。我们知道数组可以根据下标来进行随机访问,如a[0], a[1], a[2], a[3], a[4],通过这样来访问,因此其查询效率非常高。而在散列表中,当我们给出一个key的时候,也能立即查询到对应的value。这时我们就需要一个“中转站”,通过某种方式,把Key和数组下标进行转换,而这个中转站就是哈希函数。

839e0a0e425812541792c58e9cf363d.png

不同的语言中,哈希函数的实现方式是不同的。Java中使用的是HashMap

在Java及大多数的面向对象的语言中,每个对象都有属于自己的hashcode,用以区分不同的对象,而这个hashcode是一个整形变量。此时我们就需要将这个整形变量转化成数组的下标,最简单的转化方式是对数组长度进行取模。

公式如下:

index = HashCode(key) % Array.length
登录后复制

举个例子:

给出一个长度为8的数组,我们要查找key为"001121"所对应的Vaule,而"001121"的hashcode为1420036703,那么就可通过下面的计算先得到数组下标:

index = HashCode("001121")%Array.length = 1420036703 % 8 = 7
登录后复制

散列表的读写操作

1.写操作

写操作就是在散列表中插入新的键值对(jdk中叫做Entry)。

具体的做法是:通过哈希函数将key值转化为数组下标,然后在数组的该位置处插入Entry(注意是Entry键值对Key+Value,而不仅仅是Value)。可想而知,不同的key值可能会转化为相同的下标,那么此时就成为哈希冲突。

解决哈希冲突常用的方法是开放寻址法和链表法。

开放寻址法的基本思路是:当发生哈希冲突时,就把Entry放到下一个数组中为空的位置,也就是逐个往后移动。

链表法(应用在Java的HashMap集合类中)的基本思想是:数组中的每个元素不仅是一个Entry对象,同时也是一个链表的头节点。每个Entry对象通过next指针指向它的下一个Entry节点。当新来的Entry对象映射到与之冲突的数组位置时,只需要插入到对应的链表中即可。

4fda9070d54bd388af9487b0fbf72bb.png

2.读操作

读操作与写操作对应 ,只需特别处理冲突情况即可。

具体的思路为:通过哈希函数,将待查找的Key值转化为数组下标,然后检查数组中该位置的Key值是否为我们要找的Key,若是,则找到,可以返回该Entry的Value值;否则,沿着链表继续往下查找,看有没有对应的Key值。

例如,我们要查找Key为002936所对应的value时,先将Key转化为数组下标,得到下标为2,检查该元素,发现该元素的Key为002947,不是我们要查询的Key,那么继续沿着链表往下查找。

69e8c5ecdab3b0f094a8c85a0e56d45.png

3.扩容

我们知道数组扩容,是当数组中的元素个数达到数组的最大长度时需要对数组扩容,那么散列表什么时候扩容呢?

当经过多次元素插入,散列表达到一定的饱和度时,发生哈希冲突的概率会变大,此时大量的元素拥挤在相同的数组下标位置,这对后序的插入和查询操作的性能产生很大的影响,此时就需要对散列表扩容。

影响散列表扩容的因素为:

Capacity,即HashMap的当前长度

LoadFactor,即HashMap的负载因子,默认值为0.75

扩容需要满足的条件:

HashMap.Size >= Capacity X LoadFactor
登录后复制

简单解释为:当哈希表中的条目数超出了当前容量与其加载因子的乘积时,并且要存放的位置已经有元素了(哈希碰撞),这两个条件满足时,需要进项扩容,会将容量扩大为原来的两倍。加载因子默认值0.75,是在空间和时间上的一个折中,加载因子过高(发生冲突可多存放在链表),虽然减少了空间成本,但也增加了查询成本。

扩容的步骤:

扩容不是简单地把散列表的长度扩大,而是经历了下面两个步骤:

1.扩容,创建一个新的Entry空数组,长度时原数组的2倍;

2.重新Hash,遍历原Entry数组,所有的Entry重新Hash到新数组中。

经过扩容,原本拥挤的散列表重新变得稀疏,原有的Entry也重新得到了尽可能均匀的分配。需要注意的是,关于HashMap的实现,JDK8和以前的版本有着很大的不同。当多个Entry被Hash到同一个数组下标位置时,为了提高插入和查找的效率,HashMap会把Entry的链表转化为红黑树这种数据结构。

相关文章教程推荐:java语言入门

以上是java中关于散列表的详细介绍的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java 中的完美数 Java 中的完美数 Aug 30, 2024 pm 04:28 PM

Java 完美数指南。这里我们讨论定义,如何在 Java 中检查完美数?,示例和代码实现。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。这里我们通过示例讨论简介、如何使用weka java、平台类型和优点。

Java 中的史密斯数 Java 中的史密斯数 Aug 30, 2024 pm 04:28 PM

Java 史密斯数指南。这里我们讨论定义,如何在Java中检查史密斯号?带有代码实现的示例。

Java Spring 面试题 Java Spring 面试题 Aug 30, 2024 pm 04:29 PM

在本文中,我们保留了最常被问到的 Java Spring 面试问题及其详细答案。这样你就可以顺利通过面试。

突破或从Java 8流返回? 突破或从Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

Java 中的时间戳至今 Java 中的时间戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的时间戳到日期指南。这里我们还结合示例讨论了介绍以及如何在java中将时间戳转换为日期。

Java程序查找胶囊的体积 Java程序查找胶囊的体积 Feb 07, 2025 am 11:37 AM

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4

如何在Spring Tool Suite中运行第一个春季启动应用程序? 如何在Spring Tool Suite中运行第一个春季启动应用程序? Feb 07, 2025 pm 12:11 PM

Spring Boot简化了可靠,可扩展和生产就绪的Java应用的创建,从而彻底改变了Java开发。 它的“惯例惯例”方法(春季生态系统固有的惯例),最小化手动设置

See all articles