Hash表、Hash函数和HashCode

**

Hash表、Hash函数和HashCode

**

  • Hash函数和Hash表:

    Hash函数就是根据key计算出应该存储的位置,而Hash表则是基于Hash函数建立的一种查找表。给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。

  • Hash常用的构造方法:

  1. 直接寻址法:取关键字或关键字的某个线性线性函数值为散列地址。即H(key)=a*key+b这种散列函数也称为自身函数。(a和b为常数)

  2. 数字分析法:H(key)=key%用有规律(差别大)的连续数据位数。

  3. 平方取中法:关键字的每一位都有某些数字重复出现频率很高的现象,可以先求关键字(key)的平方值,通过平方扩大差异,而后取中间数位(三位)作为最终存储地址。

  • 折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。

  • HashCode:
    HashCode是object的一个方法,hashcode方法返回一个hashcode值,且这个方法是为了更好的支持hash表,比如String,Set,HashTable,HashMap等。Hashcode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。

  • HashCode性质

  • 在一个Java应用的执行期间,如果一个对象提供给equals作比较的信息没有被修改的话,该对象多次调用hashcode()方法,该方法必须始终如一返回同一个Integer。

  • 如果两个对象根据equals(object)方法是相等的,那么调用二者各自的hashcode()方法必须产生同一个Integer结果。

  • 并不要求根据equals(java.lang.object)方法不相等的两个对象,调用二者各自的hashcode()方法必须产生不同的Integer的结果。然而,程序员应该意识到对于不同的对象产生不同的Integer结果,有可能会提高hashtable的性能。

  • HashCode小结

  • 由object类定义的hashcode()方法对于不同的对象返回不同的Integer。

  • 在object类中,hashcode定义如下:public native int hashcode();

  • 了解hashcode的作用,要先知道java中的集合。
    Java中的集合(collection)有两类,一类是List,一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不重复,可两个元素是否重复应该依据什么来判断?
    这就是object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
    于是,Java采用了哈希表的原理。哈希(hash)实际上是人名,由于他提出了哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。
    当集合要添加新的元素时,先调用这个元素的hashcode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用他的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址(或以链表的形式存储)。所以这里存在一个冲突解决的问题。这样实际调用equals方法的次数就大大降低了。
    简而言之,在集合查找时,hashcode能大大降低对象比较次数,提高查找效率。

  • Java对象的equals方法和hashcode方法是这样规定的:

  1. 相等(相同)的对象必须具有相等的哈希码(或者散列码)。(解释:两个Java对象A和B,A和B相等(equals结果为true),但A和B的哈希码不同,则A和B存入hashmap时的哈希码计算得到的hashmap内部数组位置索引可能不同,那么A和B很有可能允许同时存入hashmap,显然相等/相同的元素是不允许同时存入hashmap,hashmap不允许存放重复元素。)
  2. 如果两个对象的hashcode相同,它们并不一定相同。(解释:不同对象的hashcode可能相同;两个Java对象A和B,A和B不相等(equals结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同时HashMap会在该位置建立一个链接表,将A和B串起来放在该位置,显然,该情况不违反HashMap的使用原则,是允许的。当然,哈希冲突越少越好,尽量采用好的哈希算法以避免哈希冲突。)
  • 小结
  1. 如果两个对象相同,那么它们的hashcode值一定要相同;
  2. 如果两个对象的hashcode相同,它们并不一定相同(equals比较)。否则可能出现相同的对象可以出现在set集合中,同时,增加新元素的效率会降低。
  3. equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,却并不能证明它们的hashcode()不相等。

在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当前hashcode()也就相等了;在String类型,equals()返回的是两个对象内容的比较,当两个对象内容相等时,hashcode()方法根据String类的重写代码的分析,也可知到hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。

参考:
https://www.jianshu.com/p/6eb3e2762277
https://baike.baidu.com/item/哈希表/5981869
https://www.cnblogs.com/Qian123/p/5703507.html#_label1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值