Java哈希表以及哈希冲突

Java哈希表以及哈希冲突文章目录Java哈希表概念冲突避免冲突哈希函数的设计方法常见哈希函数负载因子调节解决哈希冲突两种常见的方法是:闭散列和开散列哈希表和java类集的关系Java哈希表概念顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN),搜索的效率取决于搜索过程中元素的比较次…

大家好,又见面了,我是你们的朋友全栈君。

Java哈希表

概念

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(log N),搜索的效率取决于搜索过程中元素的比较次数。

理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。 如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。
当向该结构中:
插入元素
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
搜索元素
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功
该方式即为
哈希(散列)方法
,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(HashTable)(或者称散列表)

冲突

不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

避免冲突

*由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一
个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率。*而不能完全避免哈希冲突。

哈希函数的设计方法

引起哈希冲突的一个原因可能是:哈希函数设计不够合理。 哈希函数设计原则:

哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间
哈希函数计算出来的地址能均匀分布在整个空间中
哈希函数应该比较简单

常见哈希函数

  1. 直接定制法–(常用)
    取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B 优点:简单、均匀 缺点:需要事先知道关键字的分布情况 使用场景:适合查找比较小且连续的情况
  2. 除留余数法–(常用)
    例如:数据集合{1,7,6,4,5,9};
    哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小。
    设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址
    在这里插入图片描述
    用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快
  3. 平方取中法–(了解)
    假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址; 再比如关键字为4321,对它平方就是18671041,抽取中间的3位671(或710)作为哈希地址 平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况
  4. 折叠法–(了解)
    折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。
    折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况
  5. 随机数法–(了解)
    选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中random为随机数函数。通常应用于关键字长度不等时采用此法

负载因子调节

在这里插入图片描述
负载因子 = 0.75;

所以当冲突率达到一个无法忍受的程度时,我们需要通过降低负载因子来变相的降低冲突率。
已知哈希表中已有的关键字个数是不可变的,那我们能调整的就只有哈希表中的数组的大小。(2倍扩容)

为什么负载因是0.75

HashMap的扩容时取决于threshold, 而threshold取决于loadFactor, loadFactor(负载因子)HashMap的默认值是0.75(3/4), 那么为什么当HashMap的容量超过3/4时就需要扩容了呢? 为什么不是1/2扩容 或者 等于table.length时扩容呢?

根据统计学的结果, hash冲突是符合泊松分布的, 而冲突概率最小的是在7-8之间, 都小于百万分之一了; 所以HashMap.loadFactor选取只要在7-8之间的任意值即可,
但是为什么就选了3/4这个值?
HashMap.loadFactor的选值是3/4就能理解了, table.length * 3/4可以被优化为(table.length >> 2) << 2) – (table.length >> 2) == table.length – (table.lenght >> 2),
JAVA的位运算比乘除的效率更高, 所以取3/4在保证hash冲突小的情况下兼顾了效率;

解决哈希冲突两种常见的方法是:闭散列和开散列

解决哈希冲突两种常见的方法是:闭散列和开散列

哈希表和 java 类集的关系

  1. HashMap 和 HashSet 即 java 中利用哈希表实现的 Map 和 Set
  2. java 中使用的是哈希桶方式解决冲突的
  3. java 会在冲突链表长度大于一定阈值后,将链表转变为搜索树(红黑树)
  4. java 中计算哈希值实际上是调用的类的 hashCode 方法,进行 key 的相等性比较是调用 key 的 equals 方
    法。所以如果要用自定义类作为 HashMap 的 key 或者 HashSet 的值,必须覆写 hashCode 和 equals 方
    法,而且要做到 equals 相等的对象,hashCode 一定是一致的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150594.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • rpc接口怎么写_rpcbind服务端口

    rpc接口怎么写_rpcbind服务端口编写更安全的RPC接口前言在一般的RPC应用当中,作为开发人员一般分为了三种,第一种就是提供RPC服务的开发人员,第二种就是客户端使用RPC服务的开发人员,以及最重要的设计RPC接口和规范RPC接口的开发人员,前面的案例当中我们将三种角色融在了一起,虽然看起来非常的方便,但是非常的不利于后期的维护以及二次开发RPC接口规范如果要冲高HelloService服务,第一步需要明确服务的名字以及接口(HelloService服务在上两篇博客)constHelloServiceName=”path/to

    2022年10月13日
    0
  • 总结:关于留学网站使用laravel框架的总结

    总结:关于留学网站使用laravel框架的总结

    2021年10月20日
    43
  • IDEA 将项目打包war包[通俗易懂]

    IDEA 将项目打包war包[通俗易懂]IntelliJIDEA将项目打包war包1、准备工作IntelliJIDEA开发工具可以正常运行的Java项目2、打包war包流程使用快捷键Ctrl+Alt+Shift+s或者鼠标点击选中项目名按F4打开ProjectStructure界面选择Artifacts,点击右边+,依次选择WebApplication:Archive和For’myP…

    2025年5月28日
    1
  • rolling在舞蹈里是什么意思_机械舞和街舞有啥区别

    rolling在舞蹈里是什么意思_机械舞和街舞有啥区别原标题:这,就是街舞中的那些“Swag”十足的舞蹈类型,你了解吗?世界越来越小了,人们越靠越近,视野越来越广,局限于逼仄的小空间的时代已经一去不复返了。现在,一推门,迎面就是全世界。自去年开始,嘻哈文化开始通过综艺节目进入公众视野(中国有嘻哈),这种来自大洋彼岸的“陌生文化”随即引起了广泛的关注。尽管作为“第一个吃螃蟹的人”,《中国有嘻哈》的最终结果不尽如人意,但却为后来的综艺制作人提供了全新的视…

    2025年5月28日
    0
  • 数据库分区、分表、分库、分片[通俗易懂]

    数据库分区、分表、分库、分片[通俗易懂]一、分区的概念        数据分区是一种物理数据库的设计技术,它的目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。        分区并不是生成新的数据表,而是将表的数据均衡分摊到不同的硬盘,系统或是不同服务器存储介子中,实际上还是一张表。另外,分区可以做到将表的数据均衡到不同的地方,提高数据检索的效率,降低数据库的频繁IO压力值,分区的优点如下:1、相对于单个文件系统或是硬盘…

    2022年5月3日
    43
  • bzoj1396_bzoj3771

    bzoj1396_bzoj3771传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1396题目大意:题解:后缀自动机,只出现一次,那么就是right值为1,那么对于一段1—-L—-R来说,(L—-R)为一个最短识别子串对于(1—-L-1)则可以用R-i+1来更新,对于(L—R)则可以用R-L+1来更新,那么两个线段树来维护即可。代码:

    2022年8月12日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号