了解哈希表

散列表Hash table,也叫哈希表),是根据(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表

根据key值来直接访问数据,查找速度快

一、哈希表和字典的区别

  1. 概念与实现方式
    • 哈希表:基于哈希函数实现的数据结构,它将数据映射到一个固定位置的数组中。通过哈希函数将关键字映射为一个索引值,然后在该索引位置上进行数据的插入、查找和删除操作。
    • 字典:在Python等编程语言中,字典是内置的、使用哈希表实现的数据结构。它提供了存储键值对的功能,每个值与唯一的键相关联,可以方便地通过键来访问对应的值。
  2. 编程语言
    • 哈希表:是一种通用的数据结构,可以在多种编程语言中实现。
    • 字典:是特定编程语言(如Python)中的特定实现,提供了额外的功能和语法糖,如迭代、切片等。
  3. 顺序性
    • 哈希表:键值对通常是无序存储的,即插入的顺序不一定与遍历的顺序相同。
    • 字典:在Python中,字典维护了插入键值对的顺序,在遍历时会按照插入的顺序返回键值对。
  4. 线程安全性
    • 哈希表:在某些实现中,哈希表是线程安全的,适合在多线程环境中使用。
    • 字典:在Python中,字典是线程不安全的,因此在多线程环境中需要额外的同步机制。
  5. 数据类型处理
    • 哈希表:不是泛型的,处理数据类型时可能需要经过装箱、拆箱操作,效率相对较低。
    • 字典:是泛型的,数据不需要经过装箱、拆箱操作,效率更高。
  6. 其他特点
    • 哈希表:最大的优势在于其索引方式,经过散列处理,在数据量大的时候查找速度优势明显。
    • 字典:具有动态伸缩性,可以自动根据需要进行扩容,以适应不同数量的键值对。此外,字典可以存储不同类型的值,非常灵活。

 二、哈希函数

哈希函数(Hash Function):将哈希表中元素的关键键值映射为元素存储位置的函数。

关于整数类型的关键字,通常用到的哈希函数方法有:直接定址法、除留余数法、平方取中法、基数转换法、数字分析法、折叠法、随机数法、乘积法、点积法等。下面我们介绍几个常用的哈希函数方法。

  1. 直接定址法

    • 定义:哈希函数为关键字的线性函数,即H(key) = key 或 H(key) = a * key + b,其中a和b为常数。
    • 特点:地址集合的大小等于关键字集合的大小。
    • 应用:适用于关键字分布基本连续的情况,如从1到100岁的人口数字统计表。
  2. 除留余数法

    • 定义:取关键字被某个不大于哈希表表长m的数p除后所得的余数为哈希地址,即H(key) = key mod p,其中p <= m。
    • 特点:简单,易于实现,是实际应用中最常用的方法之一。
    • 应用:广泛应用于各种哈希表的构建中,特别是在处理冲突时。
  3. 平方取中法

    • 定义:对关键字进行平方操作,然后取中间的几位数作为哈希地址。
    • 特点:适用于关键字分布较为均匀的情况。
    • 应用:在关键字长度较短且分布较为均匀时,可以有效避免哈希冲突。
  4. 基数转换法

    • 定义:将关键字看作另一种进制的数,再转换成原来进制的数,然后选其中几位作为哈希地址。
    • 特点:通过改变进制来改变关键字的表示形式,有助于减少哈希冲突。
    • 应用:在处理关键字较长且分布不均匀时,可以通过基数转换法来优化哈希函数的性能。
  5. 数字分析法

    • 定义:如果关键字由多位字符或数字组成,可以抽取其中的某几位作为哈希地址。
    • 特点:需要根据关键字的具体分布来选择抽取的位数,以尽量减少哈希冲突。
    • 应用:在关键字具有某种规律或模式时,数字分析法可以作为一种有效的哈希函数方法。
    • 例子:假设我们有一组身份证号码作为关键字,并且注意到身份证号码中的某几位(例如最后四位)在数据集中较为分散。我们可以选择这四位作为哈希地址。
    • 假设身份证号码为123456789012345678,我们选择最后四位5678作为哈希地址。
  6. 折叠法

    • 定义:将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址。
    • 特点:适用于关键字位数较长且没有明显规律的情况。
    • 应用:在处理长字符串或长数字作为关键字时,折叠法可以作为一种有效的哈希函数方法。
    • 例子:考虑一个较长的整数关键字1234567890,我们可以将其分为两部分12345和67890,然后相加(忽略进位)得到79235作为哈希地址。
  7. 随机数法

    • 定义:取关键字的一个随机函数值作为哈希地址,即H(key) = random(key)。注意这里的随机函数实际上是伪随机函数。
    • 特点:每个关键字都对应一个固定的哈希地址,但地址的生成是随机的。
    • 应用:在关键字长度不等或关键字分布不均匀时,随机数法可以作为一种简单的哈希函数方法。
    • 例子:由于随机数法通常涉及伪随机数生成器,假设有一个伪随机数生成器能够根据关键字生成哈希地址。对于关键字“egg”,伪随机数生成器可能返回123作为哈希地址

 三、哈希冲突

哈希冲突(Hash Collision)是一种在哈希表(Hash Table)或哈希函数中可能出现的现象,它指的是两个不同的输入值(通常称为键或关键字)经过哈希函数计算后得到了相同的哈希值(哈希地址或哈希索引)。这种现象可能会导致数据检索和存储的问题,因为哈希表通常使用哈希值来确定数据在表中的位置。

简而言之就是一山有两只老虎,得避免这种情况

哈希冲突的原因主要有以下几点:

  1. 哈希函数设计不合理:如果哈希函数的设计不合理,可能会导致输入值在哈希函数计算后的分布不均匀,进而增加哈希冲突的概率。例如,某些哈希函数可能对于特定的输入模式或数据集特别敏感,导致大量不同的输入值产生相同的哈希值。
  2. 哈希表容量过小:当哈希表的容量较小,而要存储的数据较多时,就容易出现哈希冲突。因为哈希表的大小限制了可用的哈希地址的数量,当数据项的数量接近或超过哈希表的大小时,冲突的概率就会显著增加。
  3. 数据集特征:当数据集的特征与哈希函数的设计不匹配时,也可能导致哈希冲突的增加。例如,如果数据集中的键具有某种特定的模式或分布,而哈希函数没有考虑到这种模式或分布,那么就可能导致哈希冲突的增加。

为了解决哈希冲突,可以采用以下几种方法:

  1. 开放定址法:当发生哈希冲突时,通过探测哈希表中的下一个未被占用的位置,直到找到一个空槽来存储数据。具体实现包括线性探测法、平方探测法(二次探测)等。
    • 线性探测法:当所需存放值的位置被占时,往后一直加1并对哈希表长度取模,直到找到一个空余的地址。
    • 平方探测法:当所需存放值的位置被占时,会前后寻找而不是单独方向的寻找,通常使用平方数作为探测的步长。
  2. 再哈希法:同时构造多个不同的哈希函数,当发生哈希冲突时,就使用第二个、第三个等其他的哈希函数计算地址,直到不发生冲突为止。
  3. 链地址法:将所有哈希地址相同的记录都链接在同一链表中。这样,即使多个键具有相同的哈希值,它们也可以被存储在同一个链表中,而不会导致冲突。
  4. 建立公共溢出区:将哈希表分为基本表和溢出表,将发生冲突的都存放在溢出表中。这种方法将冲突的数据项存储在单独的表中,从而避免了在基本表中处理冲突的开销。


 

四、总结

  哈希表是一种高效的数据结构,它利用哈希函数将键映射到桶或槽中,以便快速访问、插入和删除数据。在实际应用中,我们需要根据具体的需求选择合适的哈希函数、处理哈希冲突的方法以及优化哈希表的性能。通过合理地设计和使用哈希表,我们可以显著提高程序的运行效率。

自律每一天,fighting
 

参考文献

算法数据结构基础——哈希表(Hash Table)-CSDN博客

来吧!一文彻底搞定哈希表!_哈希表庆哥-CSDN博客

  • 35
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值