『数据结构与算法』散列表(哈希表)

1. 什么是散列表

散列表(Hash Table)也叫哈希表,是根据给定关键字(Key)来计算出该关键字在表中存储地址的数据结构。也就是说,散列表建立了关键字与存储地址之间的一种直接映射关系,将关键字映射到表中记录的地址,这加快了查找速度。

使用函数表达式来表示,应为:hash(key)=v,其中key为关键字,hash()为散列函数,v为散列地址。

1.1 相关术语

  • 关键字(Key):关键字是散列表的查找对象,也是散列函数的参数。其可以是记录本身,也可以是记录的唯一索引,这取决于散列表的设计。
  • 散列函数(Hash Function):将关键字映射为散列表中适当存储地址的函数称为散列函数,也叫做哈希函数。
  • 散列地址(Hash Address):将关键字通过散列函数计算出的地址称为散列地址,也叫做散列值、哈希值。
  • 散列表(Hash Table):这种使用散列技术来存储数据记录的表称为散列表。
  • 散列冲突(Hash Collision):当不同的关键字具有相同的散列地址,这种现象称为冲突,也叫做哈希冲突。而这些关键字对该散列函数来说是同义词。
  • 表长:散列表的大小,即能够存储散列地址的数量。用m表示。

1.2 举个例子

一个比较通俗的例子,就是我们手机中的通讯录。通讯录用于存储联系人的姓名及电话号码信息,它是一个按照姓名首字母进行顺序排列的表。比如我们找“嬴政”就可以通过字母“Y”进行快速定位,并找到“嬴政”。

  • 在该例子中,姓名“嬴政”便是关键字
  • 取姓名的首字母的算法便是散列函数。即:hash(嬴政) = Y。
  • 通过
  • 当我们定位到“Y”地址后,不仅有“赢政”,还有“赢异人”,也就是说,通过关键字“赢异人”也能找到“Y”的地址,这种现象便是冲突。即:hash(嬴政) = hash(嬴异人) = Y。
  • 而“赢政”与“赢异人”对该散列函数来说是同义词
  • 这个用于存储联系人的通讯录便是散列表

1.3 小结

本章节介绍了散列表的概念及相关术语,并以一个通讯录的例子来加深对散列表的了解。但还有一些问题等待我们解决,那就是“散列冲突”。我们一方面可以通过精心设计散列函数来尽量减少冲突的次数,另一方面仍需要提供解决冲突的方法。后面章节会详细介绍散列函数的设计和解决冲突的方法。

2. 散列函数的设计

散列函数的设计原则应该遵循计算简单、散列地址分布均匀。下面我们介绍几种常用的散列函数的构造方法。

2.1 直接定址法

取关键字或关键字的某个线性函数值为散列地址。即hash(key) = key 或 hash(key) = a * key + b,其中a、b 为常数。这种散列函数也叫做自身函数。

如下图中,我们要获取某个岗位级别的信息,就可以使用级别减去1来作为地址,即:hash(key) = key - 1

直接定址法的优点是简单、均匀也不会产生冲突。但由于这是一种拿空间换时间的方式,所以适合查找表较小且连续的情况。比如年龄、岗位级别等。

2.2 数字分析法

通过分析一组数据,这些数据中可能出现的关键字都是事先知道的,则可以取关键字的若干数位组成散列地址。取出的这部分数据要在其数位上出现的频率小,这样出现冲突的几率就会很小。

比如手机号码,其前3位为网络识别号,中间4位为地区编码,而后4位才是真正的用户号码。那么在某个公司中,其员工的手机号码前7位出现冲突的概率会很大,而后4位出现冲突的概率会很小,则可以取后四位做为散列地址。

2.3 平方取中法

取关键字平方后的中间几位作为散列地址。该方法是一个产生伪随机数的方法,由冯·诺伊曼在1946年提出。

2.4 折叠法

将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址。这种方法比较适用于关键字位数很多的情况。

比如关键字为 1234567890,散列表的表长为3位: (1)将关键字分为4组: 123|456|789|0 (2)将它们叠加求和:123 + 456 + 789 + 0 = 1368 (3)舍去进位,得:368 ,即为最终散列地址

2.5 除留余数法

假定散列表的表长为m,取一个不大于m但最接近或等于m的质数p,通过关键字对p取模运算来转换为散列地址。散列函数为:hash(key) = key % p,其中p ≤ m。

不仅可以对关键字直接取模,也可以在折叠法、平方取中法等运算后取模。对p的选择很重要,若选择不好很容易产生冲突。

3. 散列冲突的处理方法

解决冲突的方法有几种,这里我们将讨论其中最简单的两种:开放定址法和链地址法(拉链法)。

3.1 开放定址法

将产生冲突的散列地址做为自变量,通过某种冲突解决函数得到一个新的空闲散列地址。即当产生冲突后,寻找下一个空闲的散列地址。根据寻找的方式不同又分为几种方法,下面来介绍。

3.1.1 线性探测法

当产生冲突时, 顺序探测表中下一地址,直探测到一个空闲(自由)的地址,将记录插入。若一直探测到表尾地址m-1,则下一探测地址为表首地址0。当表满的时候,则探测失败。

比如下图散列表的散列函数使用除留余数法(m=10, p=10)。那么我们顺序插入12、13、24时顺利插入到对应地址中,再插入34、44时会产生冲突,使用线发探测法,继续探测下一地址,将插入到空闲地址上。

线性探测法会造成大量元素在相邻的散列地址上“聚集”起来,使得我们要不断处理冲突,这大大降低查找和存入效率。

3.1.2 平方探测法

平方探测法是消除线性探测法中的聚集问题的一种冲突解决方法。设发生冲突的地址为d,那么使用平方探测法得到的新的地址序列为d ± 1^2、d ± 22、d ± 32...d ± ���2(key ≤ m/2)。

还是刚才那个例子,当插入34时,在下标为4的位置产生冲突,我们先计算一下在该位置探测的序列: 4 + 12 = 5、4 - 12 = 3、4 + 22 = 8、4 - 22 = 0,即:5、2、8、0,所以34应该被放到5的位置。而44应该放到8的位置。

平方探测法的缺点是不能探测到散列表上所有的地址,但至少能探测到一半地址。

3.1.3 伪随机探测法

伪随机探测法是当发生地址冲突时,地址增量为伪随机数序列。

伪随机数是说,如果我们设置随机种子相同,则不断调用随机函数可以生成不会重复的数列,我们在查找时,用同样的随机种子,它每次得到的数列是相同的,相同的地址当然可以得到相同的散列地址。

3.1.4 双散列

双散列顾名思义是使用了两个散列函数,当执行第一个散列函数得到的地址发生冲突时,则执行第二个散列函数来计算该关键字的地址增量

一种常见的算法是:(hash1(key) + i * hash2(key)) mod m,其中i为冲突次数,hash1()为第一个散列函数,hash2()为第二个散列函数,m为散列表大小。当发生冲突后,我们通过重复增加步长i来寻址。

还是以上面的例子为例。第一个散列函数为hash1(key) = key mod 10,第二个散列函数设为hash2(key) = key mod 3。

通过上面公式,可以计算出关键字34的散列地址: (34 mod 10 + 1 * (34 mod 3)) mod 10 = (4 + 1 * 1) mod 10 = 5。而关键字44的散列地址为:(44 mod 10 + 2 * (44 mod 3)) mod 10 = (4 + 2 * 2) mod 10 = 8

3.2 链地址法

链地址法又称拉链法,是利用链表来解决冲突的一种方法,即把具有相同散列地址的关键字记录存入到同一个单链表中,该链表称为同义词链表。每一个散列地址都有一个对应的链表。

还是上面的例子,使用链地址法的存储模型如下图所示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/145834.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[文件读取]shopxo 文件读取(CNVD-2021-15822)

1.1漏洞描述 漏洞编号CNVD-2021-15822漏洞类型文件读取漏洞等级⭐⭐漏洞环境VULFOCUS攻击方式 描述: ShopXO是一套开源的企业级开源电子商务系统。 ShopXO存在任意文件读取漏洞,攻击者可利用该漏洞获取敏感信息。 1.2漏洞等级 高危 1.3影响版本 ShopXO 1.4漏洞复现…

【C++】泛型编程 ① ( 函数模板 | 函数模板概念 | 函数模板意义 | 函数模板定义语法 | 函数模板调用语法 | 显式类型调用 | 自动类型推导 )

文章目录 一、函数模板简介1、函数模板概念2、函数模板意义 二、函数模板语法1、函数模板定义语法2、函数模板调用语法 三、函数模板代码示例1、代码示例2、执行结果 四、函数模板代码示例 - 声明多个泛型的情况1、代码示例2、执行结果 一、函数模板简介 1、函数模板概念 在 C …

63基于matlab的生物地理的优化器(BBO)被用作多层感知器(MLP)的训练器。

基于matlab的生物地理的优化器(BBO)被用作多层感知器(MLP)的训练器。粒子群优化(PSO)、蚁群优化(ACO)、遗传算法(GA)、进化策略(ES)和…

企业电子招投标采购系统源码之电子招投标的组成

功能模块: 待办消息,招标公告,中标公告,信息发布 描述: 全过程数字化采购管理,打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力,为外部供…

MySQL集群高可用架构之MHA

目录 一、概念: 1、MHA的工作流程: 2、MHA工作原理: 二、MHA实验: 一、概念: MHA:masterhight availabulity:基于主库的高可用环境下,实现主从复制以及故障切换 主从的架构&…

1688往微信小程序自营商城铺货商品采集API接口

一、背景介绍 随着移动互联网的快速发展,微信小程序作为一种新型的电商形态,正逐渐成为广大商家拓展销售渠道、提升品牌影响力的重要平台。然而,对于许多传统企业而言,如何将商品信息快速、准确地铺货到微信小程序自营商城是一个…

如何修复msvcr120.dll丢失问题,常用的5个解决方法分享

电脑在启动某个软件时,出现了一个错误提示,显示“msvcr120.dll丢失,无法启动软件”。这个错误通常意味着计算机上缺少了一个重要的动态链接库文件,即msvcr120.dll。 msvcr120.dll是什么 msvcr120.dll是Microsoft Visual C Redist…

文章发表 | 求臻医学发布精准肿瘤学临床试验预筛选平台

近日,求臻医学信息与人工智能团队研发的精准肿瘤学临床试验预筛选平台OncoCTMiner,在线发表于国际期刊Database: The Journal of Biological Databases and Curation (IF5.8)。OncoCTMiner集成自然语言处理(NLP)和大型语言模型&am…

Enfocus PitStop Pro 2022

Enfocus PitStop Pro是一款专为PDF编辑和优化而设计的软件,旨在帮助用户高效、准确地处理PDF文件。其功能包括但不限于: 全面的PDF编辑功能:包括添加、删除或重新排列页面,合并和分割PDF文件,以及调整页面大小和方向等…

Linux 函数库

函数库: 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢? 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去…

人工智能基础_机器学习032_多项式回归升维_原理理解---人工智能工作笔记0072

现在开始我们来看多项式回归,首先理解多维 原来我们学习的使用线性回归,其实就是一条直线对吧,那个是一维的,我们之前学的全部都是一维的对吧,是一维的,然后是多远的,因为有多个x1,x2,x3,x4... 但是比如我们有一个数据集,是上面这种,的如果用一条直线很难拟合,那么 这个时候,…

美国受教育程度最高的五大城市

许多研究表明,高等教育水平对一个城市的经济发展可起到决定性的作用。美国最繁荣、经济最活跃的地区无一例外都是拥有本科和研究生学位居民的集中地。本篇知识人网小编就为大家介绍美国受教育程度最高的五大城市。 本文根据主页菌在“Stoooges三士渡”刊载的文章整理…

通过cpolar实现外网ssh远程连接linux

现在我有个想法,就是希望通过外网能够远程连接到我的开发板。这里我们就需要使用到一种技术,内网穿透。 内网穿透是一种将内部网络中的设备通过外网进行访问的技术。在linux系统中,实现内网穿透有多种方式,其中最常见的方法是使用…

Postman还能做Mock?又学了一招!

📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…

A Gentle Introduction to Graph Neural Networks

A Gentle Introduction to Graph Neural Networks----《图神经网络入门》 图神经网络信息传递积累 图在我们身边随处可见,现实世界中的物体通常是根据它们与其他事物的联系来定义的。一组物体以及它们之间的联系可以很自然地用图来表示。十多年来,研究人…

AWS实战(一)-创建S3 存储桶

1)登录AWS账号,选择服务—>存储—>S3。 2)查看存储桶列表 3)点击"创建存储桶"创建bucket。 4)设置跨域 点击编辑,修改跨域设置即可。

工具: PowerShell常用命令

ISE: 打开ISE编辑器 echo: 输出一行信息 mkdir: 创建一个文件夹 mkdir ./MyPlugin文件相关处理 参考: powershell新手向,新建、删除文件及对文件添加内容 参考文档 PowerShell入门教程 语法、环境| Powershell 教程

【springmvc框架一文搞定】

SpringMVC框架 1. 搭建springmvc测试项目1.1 创建maven项目1.2 导入依赖pom.xml1.3 将springmvc容器加载到tomcat中1.4 启动tomcat插件1.5 访问路径: 2. 剖析启动过程2.1 启动服务器初始化过程2.2 访问路径执行过程 3.spring-springmvc bean的管理3.1 因为功能不同&…

langchain实战-hello world

一、LangChain简介 github地址: GitHub - langchain-ai/langchain: ⚡ Building applications with LLMs through composability ⚡ LangChain是一个用于开发由语言模型支持的应用程序的框架。它使应用程序能够: 具有上下文感知能力:将语言模…

BES2700H开发不完全手册

BES2700H开发不完全手册 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,群赠送语音信号处理降噪算法,ANC AEC ENC EQ BF BES蓝牙耳机音频资料 1 成功编译 2 代码 3 开放文档