Hash相关基本内容(构造函数 冲突解决)

这是我参与18月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

1.Hash表(散列表) 根据关键码值而直接进行访问的数据结构(,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度)我们可以看之前分享的查找算法主要都是通过比较来找位置,而hash在这个基础上做出了一些改变 他并没有去比较 而是通过映射函数去定位查找记录 而这个映射函数就是散列函数

2.我们在知道HASH表和HASH函数之后 我们就要进一步的思考 我们怎样来建立HASH函数呢?每一个方法有什么优劣

  • 直接定址法

可以直接通过一个线性函数就可以直接定位到关键字存放的散列表的位置(y = ax + b 其中x为关键字) 这种直接定址法就是很简单 例如我存放个年级的人数(一年级=1,二年级=2 ....) 我用y=x 就可以建立一个映射函数一一映射,但直接地址法对这种连续且数据量较小的数据比较好 但存储的关键字之间关联性不大 且不连续 用这个来存储值就会浪费很多空间 则并不适用

  • 除留去余法

这个方法应该经常用到:选择一个合适的整数P 对关键之进行除留取余来计算散列位置 H(K)=K mod p;其中p的选取是关键 因为p选的好 产生冲突的几率会很小 则查找效率就会很高 反之就很低,p最好取取不大于表长且最接近表长m素数时效果最好(素数:除了1和它本身以外不再有其他因数的自然数)

  • 平方取中法

看个例子就明白了:关键字序列是{45,34,54}平方后是{2025,1156,2916}则散列后的地址{02,15,91}

数字分析法 折叠法 随机数法这些 想要了解可以进一步网上搜索

3.在我们利用hash函数存储时出现了可能会出现冲突 下面就是冲突的解决办法

  • 线性探测法

很容易理解 发生冲突直接从下一个位置寻找散列地址 依次类推 知道找到空的散列地址就存入
H=(H(key)+d)%m,(d=1,2,3...,m-1)其中m为表长

  • 二次探测法

H=(H(key)+d)%m,(d=1^2,-1^2,2^2,-2^2,.....,q^2,-q^2,q<=根号下m) 其实时线性探测的进一步

  • 随机探测法

d为{1,2,3,...,m-1}中够成一个随机数列且从中顺序取的一个数

  • 再散列函数法

则需要构造不同得HASH函数,Hi=RH1(key) i=1,2,…,k,当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到不发生冲突

  • 链地址法

当冲突发生时 前面得冲突解决办法时移动位置去存放 而这个链地址法当产生冲突并没有去换地址,而是通过链把具有相同位置得记录链起来

例如下图显示:

image.png ( 图片来源网上)

JAVA中得HASH结构: HashMap: 在这个得基础上,我想分享以下在hashMap中对HASH得简单使用。 在HashMap中我们存值一般时

HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("test", "test");
复制代码

那来看以下hashMap的Put:

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
复制代码

注意其中的hash(key) ,其中hashCode也是Obejct中的一个方法 我们可以重写他 而hashCode则是我们所说的散列函数 他需要计算返回hash码,而在Object中hashCode方法他实际上返回的值时实例对象的内存地址(当然你可以重写他)因为实例对象的内存地址是唯一的 他们产生冲突的几率也不大。 image.png

猜你喜欢

转载自juejin.im/post/7031860484236115998