算法6-1:哈希函数

算法6-1:哈希函数

大家好,又见面了,我是全栈君。

在上章节中已经介绍了通过红黑树实现键值对数组的查询操作,复杂度是logN。

有没有性能更好的算法呢?答案是有。

基本想法就是计算keyword的哈希值,再通过哈希值直接获取相应的键值。

这样的方法的须要解决的问题是:

  • 怎样计算哈希值

  • 怎样解决哈系冲突

哈希函数

目标

依据对象中的成员变量的值,依照一定的规则计算出一个整数。这个整数就是哈希值。

哈希值最重要的两个属性是:

  • 假设a.equals(b),那么a.hashCode() == b.hashCode()

  • 理想状况下。假设!a.equals(b),那么a.hashCode() != b.hashCode()

Java中的hash

Java中的Object对象中已经包括了hashCode函数,因为全部的对象都继承自Object,因此全部的对象都有hashCode函数。该函数能返回一个整数。代表这个实例的哈希值。

Java中Integer类型的hashCode代码例如以下:

public int hashCode() {
    return value;
}

Double类型的hashCode代码例如以下:

public int hashCode() {
    long bits = doubleToLongBits(value);
    return (int)(bits ^ (bits >>> 32));
}

String类型的hashCode代码例如以下:

public int hashCode() {
    int off = offset;
    char val[] = value;
    int len = count;
    int h = 0;
    for(int i = 0; i < len; i++) {
        h = 31*h + val[off++];
    }
    return h;
}

这样的计算哈系的办法称之为Hornor哈希法。这样的方法是一种很简单的哈系算法。构造哈系冲突是很easy的。在2011年11月,有人发现Java的HashMap存在漏洞easy让黑客实现Dos攻击,它的原理就是构造大量的哈系冲突让HashMap的复杂度从1变为N,占用大量的CPU资源,BUG的具体信息戳这里:https://bugzilla.redhat.com/show_bug.cgi?

id=CVE-2012-2739

因为String是不可变的类型,因此能够对hashCode进行缓存。

自己定义类型的hash计算

public class Student {    private int number;    private String name;    private String classname;     public int hashCode() {        int hash = 17;        hash = hash*31 + name.hashCode();        classname = hash*31 + classname.hashCode();    }}

其原理就是依照Hornor哈系法将各个成员变量的哈希值连接在一起。

哈希的取模操作

取模操作就是希望让哈系值能在0 ~ M-1范围内,便于通过它来訪问数组。

第一种方法的代码例如以下:

private int hash(Key key) {    return key.hashCode() % M;}

这段代码是错的。

这样的方法使用了取余数的操作,对于负数就会产生错误。

另外一种方法的代码例如以下:

private int hash(Key key) {    return Math.abs(key.hashCode()) % M;}

这段代码中有BUG。这样的方法在hashCode为负的0x80000000时会错误发生。由于它不能取相反数。

第三种方法的代码例如以下:

private int hash(Key key) {    return (key.hashCode() & 0x7fffffff) % M;}

这样的方法才是正确的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
上一篇 2022年1月26日 下午7:00
下一篇 2022年1月26日 下午7:00


相关推荐

  • databus教程_搭建区观察记录表

    databus教程_搭建区观察记录表最近公司因需要同步oracle数据到mysql,调研了Datax对于大数据量的同步代价有些大。开源的databus需要对源码做二次开发,才可以使用,前期我们搭建后,用自带的person表做了测试。确认可行后研发更改了源码。准备工作:1.配制gradle和java2.ojdbc6-11.2.0.2.0.jar放到如下目录:databus-master/sandbox-repo/com/oracle/ojdbc6/11.2.0.2.0/更改defaultEnvironment.gradl

    2022年8月31日
    6
  • BigDecimal 比较大小

    BigDecimal 比较大小BigDecimala=newBigDecimal(101);BigDecimalb=newBigDecimal(111);//使用compareTo方法比较//注意:a、b均不能为null,否则会报空指针if(a.compareTo(b)==-1){System.out.println(“a小于b”);}if(a.compareTo(b)==0){System.out.println(“a等于b”);}if(a.compareT.

    2022年6月3日
    44
  • 智能车竞赛拿奖难吗_全国大学生智能小车竞赛

    智能车竞赛拿奖难吗_全国大学生智能小车竞赛简介:本文给出了第一轮参加线上比赛队伍信息汇总。总共包括了八个表格,分别用于组织线上比赛抽签过程所使用。关键词:智能车竞赛,线上总决赛,参赛队伍 §01基础四轮组学校名称队伍名称指导老师1指导老师2参赛队员1参赛队员2参赛队员3安徽中医药大学狂躁呼吸阚峻岭沈同平马晓豪刘迪汪忠良陆军装甲兵学院陆装四轮组魏宁王宇王浩李成光张志伟安徽信息工程学院常青竹一队刘传柱王欣桐赵吉强金子恒郑小宇青岛科技大学..

    2026年4月15日
    29
  • vue里的export default

    vue里的export default相信大家看 Vue 项目肯定会看到各种导入导出 下面来介绍一下 Vue 的模块机制 Vue 是通过 webpack 实现的模块化 因此可以使用 import 来引入模块 例如 此外 你还可以在 bulid webpack base conf js 文件中修改相关配置 意思是 你的模块可以省略 js vue json 后缀 weebpack 会在之后自动添加上 可以用 符号代替 src 字符串等 export 用来导出模块 Vue 的单文件组件通常需要导出

    2026年3月16日
    1
  • javascript跟java哪个难_javascript比java难吗?

    javascript跟java哪个难_javascript比java难吗?JavaScript 就像是一个孩子 还在成长 而 Java 更像是已经能独当一面的男子汉 所以肯定是后者更容易交流 但如果想要跟前者交流 你需要付出一些成本 但换来的可能是不一样的编程体验 本篇回答来自于阿里巴巴淘系技术部前端开发专家雷姆 说回正题 针对题主的问题 其实 JavaScript 在某些方面跟 Jav

    2026年3月18日
    3
  • 23种常用设计模式的UML类图

    23种常用设计模式的UML类图23种常用设计模式的UML类图本文UML类图参考《HeadFirst设计模式》(源码)与《设计模式:可复用面向对象软件的基础》(源码)两书中介绍的设计模式与UML图。整理常用设计模式的类图,一

    2022年6月30日
    31

发表回复

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

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