散列(Hash)表

这篇具有很好参考价值的文章主要介绍了散列(Hash)表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、散列表的基本概念

二、散列函数的构造方法

2.1直接定址法

2.2除留余数法

2.3数字分析法

2.4平方取中法

三、处理冲突的方法

3.1开放定址法

3.1.1线性探测再散列法

3.1.2平方探测法

3.1.3双散列法

3.1.4伪随机序列法

3.2链地址法(拉链法)

四、散列查找及性能分析


 

一、散列表的基本概念

散列表也叫哈希表,这两个字在下面的概念中可以互换。

散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr

(这里的地址可以是数组下标、索引或内存地址等)。

冲突散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突。

同义词:这些发生冲突的不同关键字称为同义词。

散列表:根据关键字而直接进行访问的数据结构。

也就是说,散列表建立了关键字和存储地址之间的直接映射关系。

装填因子:散列表的装填因子一般记为α,定义为一个表的装满程度,即:

散列(Hash)表

我们之前介绍的线性表和树表的查找,记录在表中的位置与记录的关键字之间不存在确定的关系,因此我们在这些表中进行查找需要进行关键字的比较。

散列查找就是利用散列表进行查找的一种方法。

散列表是怎么构成的呢?它是把关键字与表中的位置进行了关联,这种联系为散列函数。我们通过散列函数即可找到关键字的存储位置。

要直接定位存储位置自然要用数组这样的连续存储地址(或内存地址),所以用一个散列函数把许多不连续的关键字填入数组中,那就不可避免地数组中会有许多空间的浪费。好处是不用比较,时间复杂度为O(1) 。这是“空间换时间”的算法。很容易让我们想到七大基于比较的排序和基数排序、计数排序、桶排序,后三种也是“空间换时间”的算法。

不可能在任何情况下都要求O(1)的时间复杂度而使用巨大的空间,因此我们允许冲突的出现。

所以设计一个散列表,一方面构造散列函数不仅要在空间浪费适度时尽量减少这样的冲突,另一方面,这种冲突一般不可避免,我们还要设计好冲突的处理方法。

二、散列函数的构造方法

 构造散列函数的要点:

  1. 散列函数的定义域包括全部需要存储的关键字,而值域的大小范围要在散列表的大小或地址范围之内。
  2. 散列函数计算出来的地址应该能等概率、均匀地分布在整个地址空间,从而减少冲突的发生。
  3. 散列函数应尽量简单,能够在较短的时间内计算出任一关键字对应的散列地址。

2.1直接定址法

 直接取关键字的某个线性函数值为散列地址,散列函数为:

H(key)=key 或H(key)=a*key±b

式中,a 和 b 是常数。这种计算方法简单且不会发生冲突。但只适合关键字的分布基本连续的情况。

2.2除留余数法

这是一种同样简单、最常用的方法,假定散列表表长为m,取一个不大于m但最接近或等于m的质数p,散列函数为:

H(key)=key%p 或 H(key)=key MOD p  (MOD是取模运算符)

模p为最接近m的质数时造成冲突的可能性最小。

2.3数字分析法

比如学号一个班的同学前几位都是2022030XX,后两位每种数码(0,1,2...)出现的机会均等,此时应选取数码分布较为均匀的若干位作为散列地址。该方法适合于已知关键字集合,若更换了关键字(身份号),则需要重新构造新的散列函数。

2.4平方取中法

这种方法取关键字的平方值的中间几位作为散列地址。原理是一个数的平方肯定和它的每一位都有联系,我们取中间的几位作为散列地址可以使得散列地址分布比较均匀。具体取多少位要视实际情况而定。这种方法适用于关键字每位取值都不够均匀或均小于散列地址所需位数。

三、处理冲突的方法

大多数情况要保证散列函数的性能就不可避免地产生冲突。我们处理冲突的思想是为产生冲突的关键字寻找下一个空的Hash地址。

3.1开放定址法

用表示处理冲突中第 i 次探测得到的散列地址,假设得到的另一个散列地址仍然产生冲突,我们继续探测,直到不再产生冲突,则 为关键字在表中的位置。

所谓开放定址法,是指可存放新表项的空闲地址既向它的同义词表项开放,又向它的非同义词表项开放。其递推公式为:

=(H(key)+) % m

式中,H(key)为散列函数;i=0,1,2...,k(k≤m-1);m表示哈希表表长; 为增量序列。

取定某一增量后,对应的处理方法就是确定的,通常有以下四种取法: 

3.1.1线性探测再散列法

当序列为0,1,2,...,m-1时,又为线性探查法。

线性探查法可能使第 i 个散列地址的同义词存入第 i +1个散列地址,这样原本该存入第 i +1个散列地址的元素就争夺第 i +2个散列地址,....从而造成大量元素在相邻的散列地址上“聚集”(或堆积)起来,大大降低了查找的效率。

3.1.2平方探测法

 序列为,,-,,-,...,,-时,称为平方探测法,其中 k ≤m/2,散列表长度m必须是一个可以表示为4k+3的素数,又称二次探测法。

 平方探测法是一种处理冲突的较好方法,可以有效避免出现“堆积”问题,它的缺点是不能探测到散列表上的所有单元,但至少能探测到一半单元。

3.1.3双散列法

当=i * (key) 时,称为双散列法。需要使用两个散列函数,当通过第一个散列函数H(key)得到的地址发生冲突时,则利用第二个散列函数(key)计算该关键字的地址增量。

 =(H(key)+i * (key)) % m

在双散列法中,最多经过m-1次探测就会遍历表中所有位置,回到位置。

3.1.4伪随机序列法

=伪随机序列时,称为伪随机序列法。


 

在开放地址法中,不能随便物理删除表中的已有元素,因为若删除元素,则会截断其他具有相同散列地址的元素的查找地址。因此可以设置一个bool型变量对该元素进行逻辑删除

执行多次删除后,表中空闲位置较多,要维护散列表,把标记为删除的元素物理删除。

3.2链地址法(拉链法)

为了避免非同义词发生冲突,可以把所有的同义词存储在一个线性链表中,这个线性链表由其散列地址唯一标识。

散列(Hash)表

开放地址法探测数组下标空位置也算比较次数。

拉链法不同在于,找到链表指针不算比较次数。

散列表中的链地址法解决冲突时,采用的是顺序存储与链式存储相结合的方式。

四、散列查找及性能分析

  1.  虽然散列表在关键字与记录的存储位置之间建立了直接映像,但由于冲突的存在,使得散列表的查找过程仍然包含给定值与关键字进行比较的过程。因此,仍需要以平均查找长度作为衡量散列表查找效率的度量。
  2. 散列表的查找效率取决于三个因素:散列函数、处理冲突的方法和装填因子。散列(Hash)表

散列表的平均查找长度依赖于散列表的装填因子α,而不直接依赖于n或m。直观来看,α越大,表示装填的记录越“满”,发生冲突的可能性越大,反之发生冲突的可能性越小。 

题目给出散列函数,给出散列表大小边界,给出处理冲突方法。求等概率情况下平均查找长度。 

解题方法:

一、画出散列表并记录其比较次数,如

散列(Hash)表

 二、

计算成功的ASL是根据查找元素的个数来计算。

计算失败时的ASL是根据哈希函数映射的散列地址的个数来计算。

如H(key)=key mod 7,我们有0,1,2,3,4,5,6共7个。文章来源地址https://www.toymoban.com/news/detail-462725.html

到了这里,关于散列(Hash)表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 散列(Hash)表

    目录 一、散列表的基本概念 二、散列函数的构造方法 2.1直接定址法 2.2除留余数法 2.3数字分析法 2.4平方取中法 三、处理冲突的方法 3.1开放定址法 3.1.1线性探测再散列法 3.1.2平方探测法 3.1.3双散列法 3.1.4伪随机序列法 3.2链地址法(拉链法) 四、散列查找及性能分析   散列表也

    2024年02月06日
    浏览(31)
  • Hash(散列)冲突解决之线性探测再散列和二次探测再散列

    H(key) = key %13,key 为,采用开放地址法中的线性探测再散列解决冲突,依次输入11 个,16,74,60,43,54,90,46,31,29,88,77,构造哈希表 如图,例如 16%13=3,将16放入3号位置,29%13 = 3,将29放入3号位置,而此时3号位已经有元素。 就顺着表往后放,直到6号没

    2024年02月08日
    浏览(46)
  • 数据结构哈希表(散列) 之Hash

    声明: 此文章仅限于记录学习之用 , 受限于自身水平和理解能力 , 因此结论可能是不正确的. 如果您需要学习,建议参考其他文章 看了下网上一些大佬的教程, 写的云山雾绕的. 简单总结下吧. 以言简意赅为主. hash 就是把任意输入通过算法生成一个int值. 这个值就是放数据的地址

    2024年02月21日
    浏览(47)
  • C++ | 谈谈构造函数的初始化列表

    我们知道,对于下面这个类A的成员变量 _a1 和 _a2 属于【声明】,还没有在内存中为其开辟出一块空间以供存放,真正开出空间则是在【定义】的时候,那何时定义呢?也就是使用这个类A去实例化出对象的时候 这个对象的空间被开出来了,难道里面的成员变量就一定开出空间

    2023年04月11日
    浏览(100)
  • 【C++奇遇记】构造函数 | 初始化列表

    🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集 数据库专栏 初阶数据结构 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📆 未来很长,值得我们全力奔赴更美好的生活✨ 🐤本篇文章将讲授C++的初始化列表相关的知识

    2024年02月12日
    浏览(57)
  • C++中包含初始化列表的构造函数

    构造函数对初始化成员变化很有用。另一种初始化成员的方式是使用初始化列表。对于程序中接受两个参数的构造函数,其包含初始化列表的变种类似于下面这样: 格式为: :成员变量1(参数1),成员变量2(参数2) 编译器会将初始化列表一一转换成代码,并将这些代码放

    2024年02月05日
    浏览(55)
  • MySQL索引1——索引基本概念与索引结构(B树、R树、Hash等)

    目录 索引(INDEX)基本概念 索引结构分类 B+Tree树索引结构 Hash索引结构 Full-Text索引 R-Tree索引 什么是索引 索引是帮助MySQL高效获取数据的有序数据结构 为数据库表中的某些列创建索引,就是对数据库表中某些列的值通过不同的数据结构进行排序 为列建立索引之后,数据库除了

    2024年02月14日
    浏览(41)
  • 【C++】构造函数和初始化列表的性能差距

    构造函数和初始化列表的性能差距对比测试 在C++类和对象中,你可能听到过更加推荐用初始化列表来初始化类内成员。如果类内成员是自定义类型,则只能在初始化列表中调用自定义类型的构造函数。 但初始化列表和在构造函数体内直接赋值有无性能差距呢?今天就用一份

    2024年02月11日
    浏览(44)
  • C++之构造函数列表使用默认值(一百九十一)

    简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏: Audio工程师进阶系列 【 原创干货持续更新中…… 】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:An

    2024年02月09日
    浏览(79)
  • 【C++】类与对象——六个默认成员函数、构造函数的概念和特征,析构函数的概念和特征

      如果一个类中什么成员都没有,简称为空类。   空类中真的什么都没有吗?   并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。     构造函数是C++中的一

    2024年02月06日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包