【哈希表:哈希函数构造方法、哈希冲突的处理】
预测未来的最好方法就是创造它💦
目录
一、什么是Hash表
二、Hash冲突
三、Hash函数的构造方法
1. 直接定址法
2. 除余法
3. 基数转换法
4. 平方取中法
5. 折叠法
6. 移位法
7. 随机数法
四、处理冲突方法
1. 开放地址法
• 线性探测法
• 双散列函数法
2. 拉链法
一、什么是Hash表
哈希表(Hash Table),也叫散列表,是一种根据关键字直接访问内存存储位置的数据结构。它通过把关键字映射到哈希表中一个位置来访问记录,以加快查找的速度。
哈希表是由哈希函数和数组组成的,通过哈希函数将关键字转换成数组的下标,然后把该关键字存储在这个下标所对应的数组元素中,从而实现快速的查找、插入和删除操作。
二、Hash冲突
当不同的关键字被映射到同一个数组下标时,就发生了哈希冲突(Collision)。哈希表解决冲突的方式有多种,常见的方式是使用链式法(Chaining)和开放地址法(Open Addressing)。
三、Hash函数的构造方法
对于Hash函数的构造,没有特定的要求,所以方法很多,只是我们需要了解,什么样的哈希函数,才叫好的Hash函数,这样就便于我们根据实际情况来构造合理的Hash函数。
衡量一个哈希函数是否合理,是否是一个好的哈希函数,就看哈希函数对一组关键字所产生的冲突的频率有多高,如果一个哈希函数能够尽量的避免掉这些冲突,那么这个哈希函数就是一个好的哈希函数。
1. 直接定址法
取关键字或关键字的某个线性函数值为哈希地址。即:
H(key) = key 或 H(key) = a*key +b
2. 除余法
以关键码除以表元素总数后得到的余数为存储地址例:
对21,30,11三个数,利用k MOD 3的方式,求他们的哈希地址有:
21 MOD 3=0
30 MOD 3=0
11 MOD 3= 2
3. 基数转换法
将关键码看作是某个基数制上的整数,然后将其转换为另一基数制上的数,转换后得到的数据就是存储地址
例:
对21、30、11进行基数转换法求哈希地址。
假设这三个数看成是八进制数(不一定是八进制数,只是假设),转成十进制有:17、24、9
4. 平方取中法
先通过求关键字的平方值扩大相近数的差别,然后根据表长度取中间的几位数作为散列函数值。又因为一个乘积的中间几位数和乘数的每一位都相关,所以由此产生的散列地址较为均匀。
例:
对:21、30、11进行平方取中法求哈希地址(取中间的一位)。
21x21 = 441 4
30x30 = 900 0
11x11 = 121 2
5. 折叠法
折叠法是一种常见的哈希函数构造方法,其基本思想是将关键字分组后,每组相加、相乘或进行异或运算,然后得到一个总和值。最后,按照需求截取其中一段作为哈希值。
折叠法的具体实现方式如下:
-
将关键字分成若干段,每段固定长度(通常为哈希表大小),不足时可以补0或者随机数。
-
对每段进行相加、相乘或进行异或运算,得到一个中间值。
-
所有中间值相加或相乘得到一个总和值。
-
按照需求截取其中一段作为哈希值。
假设我们要将数字 12345678 转换成哈希值。为了方便起见,我们将其分成两段,每段四个数字。由于 1234 和 5678 长度相同,可以直接采用加法或者乘法的方式计算中间值。
以下是一种可能的折叠法实现方法:
-
将数字 12345678 分成两段:1234 和 5678。
-
将每段数字逆序排列得到 4321 和 8765。
-
将每段数字相加或相乘得到中间值。
例如,我们选择将每段数字相加:
-
中间值 1:4+8=12;
-
中间值 2:3+7=10;
-
中间值 3:2+6=8;
-
中间值 4:1+5=6;
-
将所有中间值相加得到总和值:12+10+8+6=36。
-
按照需求截取其中一段作为哈希值。假设哈希表大小为 10,因此选择取总和值的最后一位 6 作为哈希值。
因此,使用折叠法将数字 12345678 转换成哈希值为 6。
6. 移位法
将关键码分为多段,左边的段右移,右边的段左移,然后将它们叠加。和折叠法相似。7. 随机数法
随机数法是一种基于随机数的哈希函数构造方法,它主要通过将关键字和一个在某个范围内随机生成的常数进行运算,从而得到一个哈希值。这种方法的优势在于对大部分数据集都能够提供比较均匀的哈希分布。
假设我们有一个数字 666,现在我们想要将它映射为某个哈希表中的桶号,我们可以按照以下步骤进行:
-
选取一个随机数,假设为 x;
-
对于 666这个数字,将它与 x 相乘得到一个新的数字;
-
将这个新的数字除以桶的数量,然后将余数作为桶号返回即可。
例如,我们选取 x = 9876,并且哈希表中总共有 100 个桶。那么,使用随机数法将 666映射到相应的桶号的过程如下:
-
x = 9876
-
new_key = 666* 9876 = 6577416
-
bucket_id = new_key % 100 = 16
因此,在桶数量为 100 ,随机数为 9876 的情况下,数字 666的哈希值为 16。
需要注意的是,如果随机数选择不当,也有可能会导致哈希冲突,因此在实际应用中需要根据具体情况选择合适的随机数,并且根据哈希键值的特征做出相应的调整。
四、处理冲突方法
哈希函数在将关键字映射到桶中时,由于桶数量的限制和哈希函数本身的不可避免性质,可能会出现多个关键字映射到同一个桶中的情况,即产生了哈希冲突。为了解决这种问题,常用的处理方法有以下几种:
1. 开放地址法
开放地址法是一种简单有效的哈希冲突处理方法。当发生哈希冲突时,就尝试在哈希表中另外寻找空桶来存储该关键字,通常包括线性探测法、双散列函数法等方式,直到遇到空桶或达到最大探测次数为止。这种方法具有简单、高效的特点,但是会导致集群化、二次聚集等问题。
-
线性探测法
线性探测法是一种应用较为广泛的哈希冲突解决方法。当出现哈希冲突时,线性探测法会从当前索引值往后顺序查找下一个可以使用的空桶,并将新元素插入该空桶中。
具体而言,当哈希函数计算得到的桶已经被占用(即存在冲突)时,线性探测法通过沿着连续下一位置的方式来寻找空闲的桶。假设当前我们要插入的元素的哈希值为 h,则线性探测法的插入流程大致如下:-
如果桶 h 为空,则将元素直接存储到桶 h 中;
-
如果桶 h 不为空,则从桶 h 的下一项开始,依次检查其后面所有的相邻桶,直到找到一个空桶 k,然后将元素存储在空桶 k 中;
-
如果从桶 h 开始,依次检查完了哈希表中所有的桶,但是没有找到空桶,则认为哈希表已满,此时需要进行哈希表扩容等操作才能继续向其中添加元素。
同时,在哈希表中查询某个元素时,也需要采用类似的方式来进行查找。具体而言,查询时从哈希函数计算得到的初始桶 h 开始,逐个检查当前桶、其下一项、再下去的下一项等等直到查询到的元素或者一个空桶为止。
-
需要注意,线性探测法虽然简单,但是容易出现堆积和聚集的问题,导致哈希表的效率急剧降低。因此,在实际应用中,如果采用了线性探测法作为哈希表存储冲突处理的方法,就需要根据具体情况进行调整,以避免这种问题的发生。
-
双散列函数法
双散列函数法也是一种常见的开放地址哈希表冲突解决方法,它通过构造两个不同的哈希函数,分别计算出可能的插入位置,以此来避免冲突,并且添加新元素时按照一个固定的步长,在空桶之间线性查找下一个可以使用的位置。
具体来说,对于双散列函数法,假设我们有两个哈希函数 h1、h2,在哈希表中查找第 i 个关键字时,计算其哈希值有两种方式:-
计算第一层哈希:h1(key)=ih1(key)=i
如果第 h1(i) 个桶为空,则将关键字存储在该桶中。否则执行第二步; -
计算第二层哈希:h2(key)=1+(imod m−1)h2(key)=1+(imodm−1)
从第 h2(i) 个桶开始向后顺序查找空桶,直到找到空桶并将新元素存储在该处。
-
其中,步骤 2 中的 「1」可理解为步长,这里常常选择m - 1作为其值,m 表示哈希表的桶数。这样计算出的 h2(i) 内部等于 i+1i+1 在模mm下的余数,使得整个哈希表能够被覆盖到,不会出现漏掉某些桶的情况。
2. 拉链法
拉链法使用了链表数据结构来解决哈希冲突。具体而言,对于哈希表中的每个桶,我们不再将其存储单个元素,而是维护一个指向链表头部的指针,这个链表包含了所有映射到该桶上的关键字。
例如:
对于关键字集合{4, 11, 16, 54}和桶数 m=5,我们需要确定每一个关键字在哈希表中的存储位置。
首先可以使用某个常见的哈希函数如:h(key)=key mod p,其中 p 是一个比 m 小的素数,在这里 p=5。根据该哈希函数,我们可以求得各个关键字的哈希值:
h(4)=4 mod 5 = 4
h(11)=11 mod 5 = 1
h(16)=16 mod 5 = 1
h(54)=54 mod 5 = 4
因为 11 和 16 的哈希值相同,它们属于同一个桶,因此需要将它们分别插入到同一个链表中。最终,我们可以得到下面这张包含所有关键字的哈希表表示:
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
11 -> 16 | 4 -> 54 |
其中,表格的每一列表示一个桶,在第 i 列中的元素都是哈希值为 i 的关键字列表。
在实际情况中哈希函数和桶数的选择都需要经过合理设计和评估,我们通常需要考虑许多因素如质数选取、哈希函数效率、动态扩容、负载因子等等以保证哈希表的正常运行。
相关文章:
【哈希表:哈希函数构造方法、哈希冲突的处理】
预测未来的最好方法就是创造它💦 目录 一、什么是Hash表 二、Hash冲突 三、Hash函数的构造方法 1. 直接定址法 2. 除余法 3. 基数转换法 4. 平方取中法 5. 折叠法 6. 移位法 7. 随机数法 四、处理冲突方法 1. 开放地址法 • 线性探测法 …...

HTML5 应用程序缓存
HTML5 应用程序缓存 使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本。这意味着,你可以在没有网络连接的情况下进行访问。 什么是应用程序缓存(Application Cache)? HTML5 引…...

全国计算机等级考试三级网络技术选择题考点
目录 第一章 网络系统结构与设计的基本原则 第二章 中小型网络系统总体规划与设计方法 第三章 IP地址规划技术 第四章 路由设计基础 第五章 局域网技术基础应用 第六/七章 交换机/路由器及其配置 第八章 无线局域网技术 第九章 计算机网络信息服务系统的安装与…...

Python和VC代码实现希尔伯特变换(Hilbert transform)
文章目录前言一、希尔伯特变换是什么?二、VC中的实现原理及代码示例三、用Python代码实现总结前言 在数学和信号处理中,**希尔伯特变换(Hilbert transform)**是一个对函数产生定义域相同的函数的线性算子。 希尔伯特变换在信号处…...

嵌入式C语言语法概述
1.gcc概述 GCC全称是GUN C Compiler 随着时代的发展GCC支持的语言越来越多,它的名称变成了GNU Compiler Collection gcc的作用相当于翻译官,把程序设计语言翻译成计算机能理解的机器语言。 (1)gcc -o gcc -o (其…...

蓝桥杯第19天(Python)(疯狂刷题第3天)
题型: 1.思维题/杂题:数学公式,分析题意,找规律 2.BFS/DFS:广搜(递归实现),深搜(deque实现) 3.简单数论:模,素数(只需要…...

【数据库连接,线程,ThreadLocal三者之间的关系】
一、数据库连接与线程的关系 在实际项目中,数据库连接是很宝贵的资源,以MySQL为例,一台MySQL服务器最大连接数默认是100, 最大可以达到16384。但现实中最多是到200,再多MySQL服务器就承受不住了。因为mysql连接用的是tcp协议&…...

java 虚拟股票交易系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目
一、源码特点 JSP 虚拟股票交易系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统采用serlvetdaobean,系统具有完整的源代码和数据库,系统主要采用 B/S模式开发。 java 虚拟股票交易系统Myeclips…...
spring如何开启允许循环依赖
如何解决spring循环依赖 在Spring框架中,allowCircularReferences属性是用于控制Bean之间的循环依赖的。循环依赖是指两个或多个Bean之间相互依赖的情况,其中一个Bean依赖于另一个Bean,同时另一个Bean又依赖于第一个Bean。 allowCircularRe…...

jenkins+sonarqube+自动部署服务
一、jenkins 配置Pipeline 二、新建共享库执行脚本 共享库可以是一个普通的gitlab项目,目录结构如下 三、添加到共享库 Jenkins Dashboard–>系统管理–>系统配置–>Global Pipeline Libraries Name: 共享库名称,自定义即可; Defa…...

【算法系列之动态规划III】背包问题
背包问题 01背包指的是物品只有1个,可以选也可以不选。完全背包是物品有无数个,可以选几个也可以不选。 二维数组01背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次&…...
MONAI-LayerFactory设计与实现
LayerFactory 用于创建图层的工厂对象,这使用给定的工厂函数来实际产生类型或构建可调用程序。这些函数是通过名称来参考的,可以在任何时候添加。 用到的关键技术点: 装饰器(Decorators), 例如:property装饰器,创建…...
Thinkphp 6.0路由的定义
本节课我们来了解一下路由方面的知识,然后简单的使用一下路由的功能。 一.路由简介 1. 路由的作用就是让 URL 地址更加的规范和优雅,或者说更加简洁; 2. 设置路由对 URL 的检测、验证等一系列操作提供了极大的便利性; …...
Kafka系列之:深入理解Kafka集群调优
Kafka系列之:深入理解Kafka集群调优 一、Kafka硬件配置选择二、Kafka内存选择三、CPU选择四、网络选择五、生产者调优六、broker调优七、消费者调优八、Kafka总体调优一、Kafka硬件配置选择 服务器台数选择: 2 * (生产者峰值生产速率 * 副本数 / 100) + 1磁盘选择: Kafka…...

creator-泄漏检测之资源篇
title: creator-泄漏检测之资源篇 categories: Cocos2dx tags: [creator, 优化, 泄漏, 内存] date: 2023-03-29 14:48:48 comments: false mathjax: true toc: true creator-泄漏检测之资源篇 前篇 资源释放 - https://docs.cocos.com/creator/manual/zh/asset/release-manager…...
【DevOps】Jenkins 运行任务时遇到 FATAL:Unable to produce a script file 报错(已解决)
文章目录一、问题描述二、定位原因三、解决方案四、其他方案五、总结关键词: Jenkins、Unable to produce a script file、UnmappableCharacterException、IOException: Failed to create a temp file on一、问题描述 由于使用的 Jenkins 存在安全漏洞(…...
Web前端
WEB前端 HTMLCSSJavaScriptjQuery(js框架)Bootstrap(CSS框架)AJAXJSON 文章目录 WEB前端WEB前端三大核心技术Web开发工具文本编辑器集成开发环境(IDE)浏览器选择HTML什么是 HTML?HTML版本变迁HTML-HelloWorldHTML 文档 = 网页HTML 标签属性(Attribute)HTML 常用标签...

资源操作:Resources
文章目录1. Spring Resources概述1.2 Resource 接口1.3 Resource的实现类1.3.1 UrlResource访问网络资源1.3.2 ClassPathResource访问类路径下资源1.3.3 FileSystemResource访问文件系统资源1.3.4 ServletContextResource1.3.5、InputStreamResource1.3.6、ByteArrayResource1.…...

GDB调试的学习
很早就想在好好学一学gdb了,正好最近学算法(以前一直以为干硬件不需要什么特别厉害的算法,结果现在卷起来了。大厂面试题也有复杂一些的算法了) 下面的这些命令是别的博主总结的 GDB 调试过程_gdb调试过程_麷飞花的博客-CSDN博客…...

熵值法综合评价分析流程
熵值法综合评价分析流程 一、案例背景 当前有一份数据,是各品牌车各个维度的得分情况,现在想要使用熵值法进行综合评价,得到各品牌车的综合得分,从而进行车型优劣对比,为消费者提供购车依据。 数据如下(数…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...

【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...

ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...

spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...