hash函数原理,Java中怎么用?

想要搞清原理,首先搞清楚名称。Hash的名词解释是 剁碎的食物,杂乱无章的一大堆,动词解释是 切碎,搞砸。Hash函数的作用就是将无序的数据有序组织,也就是熵减操作。 在java语言中Hash函数的作用就是将任意对象转化成一定长度的数字,并将对象参考该数字在内存中存放对象。这样可以方便存放和获取数据。

Hash原理

参考这个例子:
根据数字特征,我们可以选择 H a s h ( k e y ) = k e y % 11 Hash(key)=key\%11 Hash(key)=key%11

于是我们可以将Hash函数结果作为内存地址存放数据。但很明显数字56和6存在地址冲突,如何解决?
直截了当,重新选怎Hash函数。可以 H a s h ( k e y ) = k e y % 100 Hash(key)=key\%100 Hash(key)=key%100,这样所有的数据都不存在冲突,但数据在内存中存放过于稀疏,造成空间浪费。所以我们可以通过不断尝试选择出兼顾查找效率和空间利用率的Hash函数。但不管怎么选择,随着数据的增多总存在碰撞的可能,此时我们可以选择合适的方法来避免碰撞。

探测法

1. 线性探测法

线性探测法就是通过线性变化求Hash值。其数学表达式是 H a s h ( k e y ) = ( H a s h 1 ( k e y ) + i ) % 11 , i = 0 , 1 , 2 , 3 … … Hash(key)=(Hash_{1}(key)+i)\%11,i=0,1,2,3…… Hash(key)=(Hash1(key)+i)%11,i=0,1,2,3
如例子中最后一个数据6,其Hash值和56的Hash值发生冲突,那就将Hash+1,此时与倒数第二个数据7发生冲突,那么Hash+1,直到不冲突为止。这种方法的缺点很明显,随着键值对增多,哈希表中会形成连续键值对,这样会导致后续添加的元素会不断探测至区间末尾,使探测时间边长,这现象成为“一次聚集”。

2. 平方探测法

平方探测法是对线性探测法的改进,主要为了避免“一次聚集”。平方探测每次跳跃 i 2 i^{2} i2步,这样元素就不会聚集在一起,数学表达式是 H a s h ( k e y ) = ( H a s h 1 ( k e y ) + i 2 ) % 11 , i = 0 , 1 , 2 , 3 … … Hash(key)=(Hash_{1}(key)+i^{2})\%11,i=0,1,2,3…… Hash(key)=(Hash1(key)+i2)%11,i=0,1,2,3
平方探测法完美避免了“一次聚集”,但Hash值相同的元素探测路径一致,并且越靠后的元素探测时间越长,这种现象就是“二次聚集”。

3. 双散列探测法

双散列探测法是为解决“二次聚集”而诞生,设计思路是用魔法打败魔法,此话怎讲? Hash函数本身就具有避免碰撞的性质,我们可以将这种效果叠加起来,其数学表达式是 H a s h ( k e y ) = ( H a s h 1 ( k e y ) + H a s h 2 ( k e y ) ∗ i ) % 11 , i = 0 , 1 , 2 , 3 , … … Hash(key)=(Hash_{1}(key)+Hash_{2}(key)*i)\%11,i=0,1,2,3,…… Hash(key)=(Hash1(key)+Hash2(key)i)%11,i=0,1,2,3,。 首次计算Hash值时,i=0,如果发生冲突,就按照1、2、3、4、……顺序尝试, 由于Hash1和Hash2函数本身发生冲突的概率就很低,叠加的结果发生冲突的概率更低。(要注意 H a s h 2 ( k e y ) Hash_{2}(key) Hash2(key)不能为零,否则在进行探测的时候将会陷入循环)

链表法

在探测法中,遇到数据碰撞就重新生成Hash值,在一维空间上来回跳跃直到寻出合适的存放位置。链表法直接了当,将发生冲突的数据使用链表的方法添加在后面。

Hash在Java中的应用

作用1:

在java中hashCode方法是Object类的native方法,返回值是int, 根据一定的规则将对象和内存物理地址对应,这样便于程序执行过程中快速定位对象。

作用2:

根据Hash函数的原理,可以得到以下性质:

  1. 两个对象相等,hashCode值一定相等。
  2. hashCode值不相等,对象一定不同。
  3. 两个不相等的对象,hashCode值可能相等,也可能不相等。

根据这些属性可以用于辅助判断两个对象是否相等,这也是Java中要求重写equals方法时必须重写hashCode方法。下面是重写equals方法之后,比较User(zhangsan,10,nan)、User2(zhangsan,10,nan)这两个对象的执行流程。

若未重写HashCode方法:

若重写HashCode方法:


比较这两个流程图,很容易发现若重写HashCode方法就可以提前很具HashCode值过滤掉不相等的对象。当对象数目较多时效果更为明显。

文章总结:

hash函数是对无序对象有序组织的手段,方便使用者组织和查找数据。java语言中也利用了这一性质,所有对象都具有一个hashCode,并将hashCode作为物理地址存储对象和查找对象,提高访问效率。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值