哈希表总结

作者: YY_Lee | 来源:发表于2019-12-05 15:39 被阅读0次

Hasb表又成散列表,用来实现立即查找数据的一种数据结构。
Hash函数:记录存放位置和数据项之间的对应关系。存储位置location = hash(key)

哈希函数要求

哈希函数有几个要求需要满足:

  • 哈希函数的定义域必须包括需要存储的全部关键码,如果哈希表允许有n个地址时,其值域必须在0到n-1之间。
  • 哈希函数计算出来的地址应该能均匀的分布在整个地址空间,即哈希函数应能以相同的概率取到0到n-1之间的每一个值。
  • 哈希函数应该是简单能在较短时间内计算出结果。
Hash冲突

key值的取值范围比哈希表地址集合大得多,因此有可能经过哈希函数计算不同的key值映射到同一个哈希地址上,这就产生冲突。

从两个方向解决哈希冲突:

  • 对应给定的key码集合,选择一个计算简单且能分补均匀的哈希函数,尽量减少哈希冲突
  • 制定解决冲突的方案
哈希函数构造方法
  • 直接定址法
    例如统计1到100岁的人口数量,以年龄作为key,哈希函数取key自身。
  • 数字分析法
    例如同一个班级里面学生的出生日期,如2000.1.01,其中前5位重复的可能性非常高,取这5位的造成hash冲突的可能性极高,那就不选择前5位,可以选择后几位。
  • 平方取中法
    取key值平方后中间几位作为哈希函数的地址,是一种常见的哈希函数构造方法。这是因为一个数平方后中间几位数和数的每一位都相关。
  • 折叠法
    将key值分割成位数相同的几部分,最后一部分可以不同,然后将这几部分叠加取和(舍去进位)作为哈希地址。
  • 除余法
    取一个最接近于n的质数p,利用以下公式把关键码转换成哈希地址:hash(key) = key % p;
  • 随机数法
    选择一个随机函数,取key的随机函数值作为哈希地址,即:hash(key) = random(key);
哈希冲突解决方法
一、开放定址法

用开放地址法解决冲突的做法是:当冲突发生时,使用某种探查技术在散列表中形成一个探查序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存入该地址单元)。查找时探查到开放的地址则表明表中无待查的关键字,即查找失败。

开放地址法的一般形式:

/*
  h(key)为散列函数,di为增量序列,m为表长
  h(key)是初始的探查位置,后续的探查位置依次是hl,h2,…,hm-1,即h(key),hl,h2,…,hm-1形成了一个探查序列。
*/
  hi=(h(key)+di)%m 1≤i≤m-1

装填因子:散列表中的元素个数与散列表大小的比值。
开放地址法堆装填因子的要求:
开放地址法要求散列表的装填因子α≤l,实用中取α为0.5到0.9之间的某个值为宜。

形成探测序列的方法:

  • 1、线性探查法(Linear Probing)
    将散列表T[0..m-1]看成是一个循环向量,若初始探查的地址为d(即h(key)=d),则最长的探查序列为:
    d,d+l,d+2,…,m-1,0,1,…,d-1
    即:探查时从地址d开始,首先探查T[d],然后依次探查T[d+1],…,直到T[m-1],此后又循环到T[0],T[1],…,直到探查到T[d-1]为止。

探查过程终止于三种情况:
(1)若当前探查的单元为空,则表示查找失败(若是插入则将key写入其中);
(2)若当前探查的单元中含有key,则查找成功,但对于插入意味着失败;
(3)若探查到T[d-1]时仍未发现空单元也未找到key,则无论是查找还是插入均意味着失败(此时表满)。

线性探查法的探查序列为:
hi=(h(key)+i)%m 0≤i≤m-1 //即di=i

  • 2、二次探查法(Quadratic Probing)
    二次探查法的探查序列是:hi=(h(key)+i*i)%m 0≤i≤m-1 //即di=i2
    即探查序列为d=h(key),d+12,d+22,…,等。该方法的缺陷是不易探查到整个散列空间。

  • 3、双重散列法(Double Hashing)
    该方法是开放地址法中最好的方法之一,它的探查序列是:hi=(h(key)+ih1(key))%m 0≤i≤m-1 //即di=ih1(key)
    即探查序列为:d=h(key),(d+h1(key))%m,(d+2h1(key))%m,…,等。
    该方法使用了两个散列函数h(key)和h1(key),故也称为双散列函数探查法。

二、 拉链法

拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。即每个位置上存放的是一个单链表,相同的地址的元素依次是链表上的节点。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。

拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可;

拉链法的缺点是:指针需要额外的空间,当结点规模较小时,开放定址法较为节省空间,而若将节省的指针空间用来扩大散列表的规模,可使装填因子变小,这又减少了开放定址法中的冲突,从而提高平均查找速度。

三、多哈希法

设计二种甚至多种哈希函数,可以避免冲突,但是冲突几率还是有的,函数设计的越好或越多都可以将几率降到最低(除非人品太差,否则几乎不可能冲突)。

参考文献:再散列法

相关文章

  • 哈希表总结

    哈希表也称为散列表,是根据关键字值(key value)而直接进行访问的数据结构。也就是说,它通过把关键字值映射到...

  • 哈希表总结

    Hasb表又成散列表,用来实现立即查找数据的一种数据结构。Hash函数:记录存放位置和数据项之间的对应关系。存储位...

  • 哈希表总结

    特点 用于存取要求时间复杂度为1的场景。常用于键值对存取的高级语言中,比如各种map,set,dictionary...

  • 4.数据库索引概述

    总结: 1. 索引的作用:提高数据查询效率 2. 常见索引模型:哈希表、有序数组、搜索树 3. 哈希表:以键 - ...

  • LeetCode的sum问题

    这里写几个sum问题的总结。首先是leetcode 1:two sum解法很简单,就是哈希表。哈希表的查找速度是O...

  • Java数据结构_哈希表_基本概念

    本文目标 哈希表的基本概念,哈希冲突,哈希函数 什么是哈希表 哈希表也叫做散列表(hash有剁碎的意思)哈希表是空...

  • redis数据结构--字典

    Redis的字典底层就是哈希表。 哈希表 首先给出哈希表的定义: 其中可以看到,table是一个哈希表节点的数组,...

  • 哈希表和链表

    优秀文章:Chapter: 散列表(哈希表) 一、哈希表 哈希表hashtable(key,value) 就是把K...

  • 算法-哈希表算法总结

    1 哈希表模拟 思路:通过设计哈希表,模拟O(1)时间复杂度的哈希表。 2 数组作为哈希表 思路:数组就是简单的哈...

  • 数据结构 -- 哈希表及其应用

    这篇主要用来记录一下学习到的关于哈希表的知识点。 文章结构 哈希表 哈希表的定义 哈希表的优缺点 哈希碰撞 负载因...

网友评论

    本文标题:哈希表总结

    本文链接:https://www.haomeiwen.com/subject/lmnhhqtx.html