0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

哈希表是什么?为什么需要使用哈希表

Wildesbeast 来源:网络整理 作者:佚名 2020-04-06 13:50 次阅读

我们在这篇文章将要学习最有用的数据结构之一—哈希表,哈希表的英文叫 Hash Table,也可以称为散列表或者Hash 表。

哈希表用的是数组支持按照下标随机访问数据的特性,所以哈希表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。

哈希表存储的是由键(key)和值(value)组成的数据。例如,我们将每个人的性别作为数据进行存储,键为人名,值为对应的性别,其中 M 表示性别为男,F 表示性别为女。

为什么需要哈希表?

为了和哈希表进行对比,我们先将这些数据存储在数组中。

此处准备了6个箱子(即长度为6的数组)来存储数据,假设我们需要查询 Ally 的性别,由于不知道 Ally 的数据存储在哪个箱子里,所以只能从头开始查询,这个操作便叫作线性查找。一般来说,我们可以把键当成数据的标识符,把值当成数据的内容。

从 0 号箱子开始查找,发现 0 号箱子中存储的键是 Joe 而不是 Ally,因此接着查找 1 号箱子。

哦豁,1 号箱子中的也不是 Ally,没办法,只能接着往下找。

有点小糟糕,2 号、3 号箱子中的也都不是 Ally。

功夫不负有心人,当我们查找到 4 号箱子的时候,发现其中数据的键为 Ally,把键对应的值取出,我们就知道 Ally 的性别为女(F)。

通过上面的查找过程,我们发现数据量越多,线性查找耗费的时间就越长。由此可知:由于数据的查询较为耗时,所以此处并不适合使用数组来存储数据。

但使用哈希表便可以解决这个问题,首先准备好数组,这次我们用 5 个箱子的数组来存储数据。

尝试把 Joe 存进去,使用哈希函数(Hash)计算 Joe 的键,也就是字符串 Joe 的哈希值,比如得到的结果为4928。

将得到的哈希值除以数组的长度 5,求得其余数,这样的求余运算叫作mod运算,此处mod运算的结果为3。

因此,我们将 Joe 的数据存进数组的 3 号箱子中,重复前面的操作,将其他数据也存进数组中。

Sue 键的哈希值为 7291, mod 5 的结果为 1,将 Sue 的数据存进 1 号箱中。

Dan 键的哈希值为 1539, mod 5 的结果为 4,将 Dan 的数据存进 4 号箱中。

Nell 键的哈希值为 6276, mod 5 的结果为 1,本应将其存进数组的 1 号箱中,但此时 1 号箱中已经存储了 Sue 的数据,这种存储位置重复了的情况便叫作冲突。

遇到这种情况,可使用链表在已有数据的后面继续存储新的数据(链表法)。

Ally 键的哈希值为 9143, mod 5 的结果为 3,本应将其存储在数组的 3 号箱中,但 3 号箱中已经有了 Joe 的数据,所以使用链表,在其后面存储 Ally 的数据。

Bob 键的哈希值为 5278, mod 5 的结果为 3,本应将其存储在数组的 3 号箱中,但 3 号箱中已经有了 Joe 和 Ally 的数据,所以使用链表,在 Ally 的后面继续存储 Bob 的数据。

像这样存储完所有数据,哈希表也就制作完成了。

接下来讲解数据的查询方法,假设我们要查询 Dan 的性别。

为了知道 Dan 存储在哪个箱子里,首先需要算出 Dan 键的哈希值,然后对其进行 mod 运算,最后得到的结果为 4,于是我们知道了它存储在 4 号箱中。

查看 4 号箱可知,其中的数据的键与 Dan 一致,于是取出对应的值,由此我们便知道了 Dan 的性别为男(M)。

那么,想要查询 Ally 的性别时该怎么做呢?为了找到它的存储位置,先要算出 Ally 键的哈希值,再对其进行 mod 运算,最终得到的结果为 3。

然而 3 号箱中数据的键是 Joe 而不是 Ally,此时便需要对 Joe 所在的链表进行线性查找。

于是我们找到了键为 Ally 的数据,取出其对应的值,便知道了 Ally 的性别为女(F)。

哈希冲突

在哈希表中,我们可以利用哈希函数快速访问到数组中的目标数据。如果发生哈希冲突,就使用链表进行存储,这样一来,不管数据量为多少,我们都能够灵活应对。

如果数组的空间太小,使用哈希表的时候就容易发生冲突,线性查找的使用频率也会更高;反过来,如果数组的空间太大,就会出现很多空箱子,造成内存的浪费。因此,给数组设定合适的空间非常重要。

在存储数据的过程中,如果发生冲突,可以利用链表在已有数据的后面插入新数据来解决冲突,这种方法被称为链表法,也被称为链地址法。

其中在 Java 集合类的 HashMap 中解决冲突的方法就是采用的链表法,建议阅读 HashMap 源码。

除了链地址法以外,还有几种解决冲突的方法。其中,应用较为广泛的是开放地址法,或称为开放寻址法。这种方法是指当冲突发生时,立刻计算出一个候补地址(数组上的位置)并将数据存进去。如果仍然有冲突,便继续计算下一个候补地址,直到有空地址为止,可以通过多次使用哈希函数或线性探测法等方法计算候补地址。

在 Java 中,ThreadLocal所使用的就是开放地址法。

哈希函数设计的好坏决定了哈希冲突的概率,也就决定哈希表的性能。

总结

这篇文章主要讲了一些比较基础的哈希表知识,包括哈希表的由来、哈希冲突的解决方法。

哈希表也叫散列表,来源于数组,它借助哈希函数对数组这种数据结构进行扩展,利用的是数组支持按照下标随机访问元素的特性,是存储 Key-Value 映射的集合。

哈希表两个核心问题是哈希函数设计和哈希冲突解决。对于某一个 Key,哈希表可以在接近 O(1) 的时间内进行读写操作。哈希表通过哈希函数实现 Key 和数组下标的转换,通过开放寻址法和链表法来解决哈希冲突。哈希函数设计的好坏决定了哈希冲突的概率,也就决定哈希表的性能。

有兴趣的可以在 JDK 中阅读 HashMap 的源码,在 JDK 8 和之前的版本的实现还有许多不多,比如在 JDK 8 中,引入红黑树,当链表长度太长(默认超过 8)时,链表就转换为红黑树,就可以利用红黑树快速增删改查的特点,提高 HashMap 的性能。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据存储
    +关注

    关注

    5

    文章

    977

    浏览量

    50955
  • 函数
    +关注

    关注

    3

    文章

    4338

    浏览量

    62736
  • 数据结构
    +关注

    关注

    3

    文章

    573

    浏览量

    40154
收藏 人收藏

    评论

    相关推荐

    直流快充(超充)桩,都在用什么电能?# 充电桩 # 电能

    电能
    瑞银电子
    发布于 :2024年12月26日 17:31:03

    原来压力的作用这么重要!

    压力
    华泰天科
    发布于 :2024年12月14日 14:13:35

    扫描功能有什么作用?如何使用呢? #源 #使用教程 #源维修

    安泰仪器维修
    发布于 :2024年12月09日 17:29:41

    在ADS4142的数据第18页, 4中,tSU和tH是怎么定义的?

    在我的设计中要用到一个ADC 后面连接一个隔离器和DAC,结构如下: 其中: ADC:ADS4142 DAC:DAC5672 在ADS4142的数据第18页, 4中,tSU和tH是怎么定义
    发表于 12-06 06:38

    华纳云:Chord算法如何管理节点间的联系?

    Chord算法是一种分布式哈希(DHT)协议,它通过构建一个环状结构来管理节点间的联系。以下是Chord算法如何管理节点间联系的具体方式: 环状结构: Chord算法将所有节点和键映射到一个环状
    发表于 11-08 16:03

    如何提升SoC的安全性

    进行数字签名。Bootloader在启动时使用存储在芯片中的公钥验证签名,以确保固件的真实性和完整性。通过哈希算法(如SHA-256)计算固件的哈希值,并与预先存储的正确哈希值进行比较,防止固件被篡改。
    的头像 发表于 10-21 14:19 272次阅读

    什么是默克尔树(Merkle Tree)?如何计算默克尔根?

    01 默克尔树的概念 默克尔树(Merkle Tree)是一种特殊的二叉树,它的每个节点都存储了一个数据块的哈希值。哈希值是一种可以将任意长度的数据转换为固定长度的字符串的算法,它具有唯一性和不可
    的头像 发表于 09-30 18:22 993次阅读
    什么是默克尔树(Merkle Tree)?如何计算默克尔根?

    “不需要的工业网关” 深控技术物联网解决方案

    “不需要的工业网关” 物联网解决方案
    的头像 发表于 09-29 15:43 385次阅读
    “不<b class='flag-5'>需要</b>点<b class='flag-5'>表</b>的工业网关” 深控技术物联网解决方案

    开源物联网技术--哈希算法MD5加密功能技术分享

    MD5(Message-Digest Algorithm 5)是一种常用的哈希函数,通常用于数据加密和安全校验等场合。MD5 算法可以将任意长度的消息输入计算出一个固定长度的摘要,其生成的摘要具有
    的头像 发表于 09-21 09:57 1768次阅读
    开源物联网技术--<b class='flag-5'>哈希</b>算法MD5加密功能技术分享

    ESP8266如何避免固件损坏?

    我们需要在固件下载中采用强大的固件升级方法,我们知道在固件下载中有一个示例。 例子/at_upgrade.c 对于该示例,我们有一个问题: 如何避免损坏的bin文件? 因为如果恶意用户将损坏
    发表于 07-19 06:00

    吉时利2400源电压怎么调

    功能和高精度、高稳定性等特点。 吉时利2400源(Keithley 2400 SourceMeter)是一款高性能的源测量单元(SMU),它可以作为电压源、电流源、电压和电流使用。在调整吉时利2400源
    的头像 发表于 05-23 17:06 805次阅读
    吉时利2400源<b class='flag-5'>表</b>电压怎么调

    PD电流

    PD电流
    蛋黄酥
    发布于 :2024年02月24日 20:20:13

    CAN总线系统需要使用中继器进行信号增强和延长?

    CAN总线系统需要使用中继器进行信号增强和延长? CAN总线系统是是一种用于微控制器和设备之间通信的串行总线系统。作为一种主要用于汽车和工业领域的通信协议,CAN总线系统需要使用中继器进行信号增强
    的头像 发表于 01-31 13:46 949次阅读