【数据结构】哈希表(散列表)算法原理

目录

哈希表

哈希表定义

哈希表(散列表)的基本概念

基本思想:

优点:

缺点:

散列方法:

散列函数:

散列表:

冲突:

同义词:

哈希表基本思路:

哈希冲突:

哈希表设计

哈希表结构 

哈希表创建

哈希表插入

哈希表查找

哈希冲突产生因素

1.与装填因子α有关

2.与所采用的哈希函数有关

3.与解决冲突的哈希冲突函数(方法)有关。

 哈希函数的构造方法

目的

1. 直接定址法

2. 除留余数法

3. 数字分析法

4.平方取中法

5.折叠法

哈希冲突解决方法

1. 开放定址法

(1)线性探测法

(2)平方探测法

(3)伪随机探测

2. 拉链法


哈希表

  • 哈希表定义

    • 哈希表(Hash Table)又称散列表,是除顺序表存储结构、链接表存储结构和索引表存储结构之外的又一种存储线性表的存储结构。
  • 哈希表(散列表)的基本概念

    • 基本思想:

      • 记录的存储位置与关键字之间存在对应关系
    • 优点:

      • 查找效率高
    • 缺点:

      • 空间效率低
    • 散列方法:

      • 选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放;
      • 查找时,由同一个函数对给定 k 计算地址,将 k 地址单元中有关元素关键码进行对比,确定查找是否成功。
    • 散列函数:

      • 散列方法中使用的转换函数
    • 散列表:

      • (按上述思想构成的表)根据关键码值(Key)直接进行访问的数据结构。
      • 也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
      • 这个映射函数叫做散列函数,存放记录的数组叫做散列表。
    • 冲突:

      • 不同的关键码映射到同一个散列地址
    • 同义词:

      • 具有相同函数值的多个关键字
  • 哈希表基本思路:

    • 设要存储的对象个数为n,设置一个长度为m(m≥n)的连续内存单元。
    • 以线性表中每个对象的关键字ki(0≤i≤n-1)为自变量,通过一个称为哈希函数的函数h(ki),把ki映射为内存单元的地址(或称下标)h(ki),并把该对象存储在这个内存单元中。
    • h(ki)也称为哈希地址(又称散列地址)。
    • 把如此构造的线性表存储结构称为哈希表。
  • 哈希冲突:

    • 对于两个关键字ki和kj(i≠j),有ki≠kj(i≠j),但会出现h(ki)=h(kj)。
    • 通常把这种具有不同关键字而具有相同哈希地址的对象称做“同义词”,由同义词引起的冲突称作同义词冲突。
    • 在哈希表存储结构的存储中,同义词冲突是很难避免的,除非关键字的变化区间小于等于哈希地址的变化区间,而这种情况当关键字取值不连续时是非常浪费存储空间的。
      • 就是当使用哈希函数计算哈希地址时,函数计算产生的哈希值是有限的,而数据可能比较多,导致产生了误差从而不同的关键字计算得出了相同的哈希地址
    • 通常的实际情况是关键字的取值区间远大于哈希地址的变化区间。
  • 哈希表设计

    •   哈希表设计主要需要解决哈希冲突。实际中哈希冲突是难以避免的
    • 哈希表结构 

       

    • 哈希表创建

       

    • 哈希表插入

       

    • 哈希表查找

       

    • 哈希冲突产生因素

      • 1.与装填因子α有关

        • 装填因子α是指哈希表中已存入的元素数n与哈希地址空间大小m的比值,即α=n/m
          • 装填因子α=存储的记录个数n/哈希表的大小m=n/m 
          • α越小,冲突的可能性就越小,α越小说明存储存储的记录数越少或哈希表大小越大,关键字的变化区间就会小于等于哈希地址的变化区间;
          • α越大(最大可取1),冲突的可能性就越大,α越大说明存储存储的记录数越多或哈希表大小越小,关键字的取值区间远大于哈希地址的变化区间。
        • 这很容易理解,因为α越小,哈希表中空闲单元的比例就越大,所以待插入元素同已插入的元素发生冲突的可能性就越小;
        • 反之, α越大,哈希表中空闲单元的比例就越小,所以待插入元素同已插入的元素冲突的可能性就越大;
        • 另一方面, α越小,存储空间的利用率就越低;反之,存储空间的利用率也就越高。
        • 为了既兼顾减少冲突的发生,又兼顾提高存储空间的利用率这两个方面,通常使最终的控制在0.6~0.9的范围内。
      • 2.与所采用的哈希函数有关

        • 若哈希函数选择得当,就可使哈希地址尽可能均匀地分布在哈希地址空间上,从而减少冲突的发生;
        • 否则,若哈希函数选择不当,就可能使哈希地址集中于某些区域,从而加大冲突的发生。
      • 3.与解决冲突的哈希冲突函数(方法)有关。

        • 解决冲突的哈希冲突函数(方法)选择的好坏也将减少或增加发生冲突的可能性。
    •  哈希函数的构造方法

      • 目的

        • 构造哈希函数的目标是使得到的哈希地址尽可能均匀地分布在n个连续内存单元地址上,同时使计算过程尽可能简单以达到尽可能高的时间效率。
      • 根据关键字结构和分布可以构造出很多种不同的哈希函数
      • 1. 直接定址法

        • 直接定址法是以关键字k本身或关键字加上某个数值常量c作为哈希地址的方法。
        • 直接定址法的哈希函数h(k)为:
          • h(k)=k+c
          • 如:h(学号) = 学号-201001001
        • 这种哈希函数计算简单,并且不可能有冲突发生。
        • 使用条件
          • 当关键字的分布基本连续时,可用直接定址法的哈希函数;
          • 否则,若关键字分布不连续将造成内存单元的大量浪费。
      • 2. 除留余数法

        • 除留余数法是用关键字k除以某个不大于哈希表长度m的数p所得的余数作为哈希地址的方法。
          • 除留余数法使得每个关键字通过该函数转换后映射到哈希表范围内的任意地址上的概率相等(把n个记录按关键字值映射到0~m-1的哈希空间中),从而尽可能减少发生冲突的可能性
        • 除留余数法的哈希函数h(k)为:
          • h(k)=k mod p  (mod为求余运算,即k%p,p≤m)
          • p最好是不大于哈希表长度m的质数(素数)。
      • 3. 数字分析法

        • 该方法是提取关键字中取值较均匀的数字位作为哈希地址的方法。

           

        • 条件
          • 它适合于所有关键字值都已知的情况,并需要对关键字中每一位的取值分布情况进行分析。
        • 例如

           

          • 对于一组关键字:{92317602,92326875,92739628,92343634,92706816,92774638,92381262,92394220}
          • 通过分析可知,每个关键字从左到右的第1、2、3位和第6位取值较集中,不宜作为哈希函数,剩余的第4、5、7和8位取值较分散,可根据实际需要取其中的若干位作为哈希地址。
          • 若取最后两位作为哈希地址,则哈希地址的集合为{2,75,28,34,16,38,62,20}。
      • 4.平方取中法

        • 假设关键字是1234,那它的平方就是1522756,再抽取中间的3位就是277
        • 条件
          • 适合不知道关键字的分布,而位数又不是很大的情况。
      • 5.折叠法

        • 将关键字从左到右分割成位数相等的几个部分,然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。
        • 比如关键字是9876543210,散列表表长为三位,我们将它分成四组,987|654|321|0,然后将他们叠加求和等于1962,再求后三位得到散列地址962。
        • 条件
          • 适合事先不知道关键字的分布,关键字位数叫多的情况。
    • 哈希冲突解决方法

      • 1. 开放定址法

        • 开放定址法是一类以发生冲突的哈希地址为自变量,通过某种哈希冲突函数得到一个新的空闲的哈希地址的方法。
        • 开放定址法中哈希表空闲单元既向同义词关键字开放又向发生冲突的非同义词开放
          • 哈希表中的一个地址存放的是同义词还是非同义词要看是谁先占用他,和构造哈希表元素排列顺序有关
        • 根据冲突地址找到新的空闲哈希地址的方法有线性探测法、平方探测法、未随机序列法、双哈希函数法等
        • (1)线性探测法

          • 线性探测法是从发生冲突的地址(设为d)开始,依次探测d的下一个地址(当到达下标为m-1的哈希表表尾时,下一个探测的地址是表首地址0,任何依次探测0-d的位置),直到找到一个空闲单元为止(当m≥n时一定能找到一个空闲单元)。
          • 线性探测法的数学递推描述公式为:
            • d0=h(k)
            • di=(di-1+1) mod m  (1≤i≤m-1)
            • 模m是为了保证找到的位置在0~m-1的有效空间中。
          • 堆积问题
            •  当连续出现若干个同义词时(设第一个同义词占用单元d0),这连续的若干个同义词,将占用哈希表的d0、d0+1、d0+2等单元,随后任何本该在d0、d0+1、d0+2等单元上的哈希映射都会由于前面的同义词堆积而产生冲突,尽管随后的这些关键字并没有同义词
          • 非同义词冲突:
            • 采用线性探测法的缺点是可能产生非同义词冲突
            • 哈希函数值不相同的两个记录争夺同一个后继哈希地址,这是由于堆积(或聚集)现象引起的。
        • (2)平方探测法

          • 设发生冲突的地址为d0,则平方探测法的探测序列为:d0+1²,d0-1²,d0+2²,d0-2²…。
          • 平方探测法的数学描述公式为:
            • d0=h(k)
            • di=(d0± i²) mod m  (1≤i≤m-1)
          • 平方探测法是一种较好的处理冲突的方法,可以避免出现堆积问题。
            • 因为是在当前冲突地址的基础上进行平方相加,避免了发生冲突在同一位置区间查找空余位置
          • 它的缺点是不能探测到哈希表上的所有单元,但至少能探测到一半单元。
        • (3)伪随机探测

          • 按顺序决定哈希值时,如果发生冲突,通过随机函数生成一个数,在原来哈希值的基础上加上随机数,直到该哈希值不发生冲突
      • 2. 拉链法

        • 拉链法是把所有的同义词用单链表链接起来的方法。
        • 拉链法中,哈希表每个单元中存放的不再是记录本身,而是相应同义词单链表的头指针。

           

        • 由于单链表中可插入任意多个节点,所以拉链法的装填因子α根据同义词的多少既可以设定为大于1,也可以设定为小于或等于1,通常取α=1。
        • 优点
          •  拉链法处理冲突简单且无堆积现象,即非同义词绝不会发生冲突,因此平均查找长度较短
          • 由于拉链法中个单链表上的节点空间是动态申请的,故他更合适于造表前无法确定表长的情况
          • 开放定值法为减少冲突要求装填因子α较小,故当数据规模较大时会浪费很多空间,而拉链法中可取α>=1,且元素较大时拉链法中增加的指针与可忽略不计,因此节省空间
          • 在用拉链法构造的哈希表中进行删除节点的操作,更加容易实现
        • 缺点
          • 指针需要额外的空间,故当元素规模较小时开放定值法较为节省空间,若将节省的指针空间用来扩大,哈希表的规模可使装填因子α变小,这又减少了开放定值法中的冲突,从而提高了平均查找速度
  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

列队猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值