当前位置: 首页 > news >正文

【哈希表:哈希函数构造方法、哈希冲突的处理】

预测未来的最好方法就是创造它💦

目录

一、什么是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. 折叠法

  折叠法是一种常见的哈希函数构造方法,其基本思想是将关键字分组后,每组相加、相乘或进行异或运算,然后得到一个总和值。最后,按照需求截取其中一段作为哈希值。

折叠法的具体实现方式如下:

  1. 将关键字分成若干段,每段固定长度(通常为哈希表大小),不足时可以补0或者随机数。

  2. 对每段进行相加、相乘或进行异或运算,得到一个中间值。

  3. 所有中间值相加或相乘得到一个总和值。

  4. 按照需求截取其中一段作为哈希值。


  假设我们要将数字 12345678 转换成哈希值。为了方便起见,我们将其分成两段,每段四个数字。由于 1234 和 5678 长度相同,可以直接采用加法或者乘法的方式计算中间值。

以下是一种可能的折叠法实现方法:

  1. 将数字 12345678 分成两段:1234 和 5678。

  2. 将每段数字逆序排列得到 4321 和 8765。

  3. 将每段数字相加或相乘得到中间值。

 例如,我们选择将每段数字相加:

  • 中间值 1:4+8=12;

  • 中间值 2:3+7=10;

  • 中间值 3:2+6=8;

  • 中间值 4:1+5=6;

  1. 将所有中间值相加得到总和值:12+10+8+6=36。

  2. 按照需求截取其中一段作为哈希值。假设哈希表大小为 10,因此选择取总和值的最后一位 6 作为哈希值。

因此,使用折叠法将数字 12345678 转换成哈希值为 6。

6. 移位法
  将关键码分为多段,左边的段右移,右边的段左移,然后将它们叠加。和折叠法相似。
7. 随机数法

  随机数法是一种基于随机数的哈希函数构造方法,它主要通过将关键字和一个在某个范围内随机生成的常数进行运算,从而得到一个哈希值。这种方法的优势在于对大部分数据集都能够提供比较均匀的哈希分布。

  假设我们有一个数字 666,现在我们想要将它映射为某个哈希表中的桶号,我们可以按照以下步骤进行:

  1. 选取一个随机数,假设为 x;

  2. 对于 666这个数字,将它与 x 相乘得到一个新的数字;

  3. 将这个新的数字除以桶的数量,然后将余数作为桶号返回即可。

例如,我们选取 x = 9876,并且哈希表中总共有 100 个桶。那么,使用随机数法将 666映射到相应的桶号的过程如下:

  1. x = 9876

  2. new_key = 666* 9876 = 6577416

  3. bucket_id = new_key % 100 = 16

因此,在桶数量为 100 ,随机数为 9876 的情况下,数字 666的哈希值为 16。

需要注意的是,如果随机数选择不当,也有可能会导致哈希冲突,因此在实际应用中需要根据具体情况选择合适的随机数,并且根据哈希键值的特征做出相应的调整。

四、处理冲突方法

  哈希函数在将关键字映射到桶中时,由于桶数量的限制和哈希函数本身的不可避免性质,可能会出现多个关键字映射到同一个桶中的情况,即产生了哈希冲突。为了解决这种问题,常用的处理方法有以下几种:

1. 开放地址法

  开放地址法是一种简单有效的哈希冲突处理方法。当发生哈希冲突时,就尝试在哈希表中另外寻找空桶来存储该关键字,通常包括线性探测法、双散列函数法等方式,直到遇到空桶或达到最大探测次数为止。这种方法具有简单、高效的特点,但是会导致集群化、二次聚集等问题。

  1. 线性探测法
      线性探测法是一种应用较为广泛的哈希冲突解决方法。当出现哈希冲突时,线性探测法会从当前索引值往后顺序查找下一个可以使用的空桶,并将新元素插入该空桶中。
      具体而言,当哈希函数计算得到的桶已经被占用(即存在冲突)时,线性探测法通过沿着连续下一位置的方式来寻找空闲的桶。假设当前我们要插入的元素的哈希值为 h,则线性探测法的插入流程大致如下:

    1. 如果桶 h 为空,则将元素直接存储到桶 h 中;

    2. 如果桶 h 不为空,则从桶 h 的下一项开始,依次检查其后面所有的相邻桶,直到找到一个空桶 k,然后将元素存储在空桶 k 中;

    3. 如果从桶 h 开始,依次检查完了哈希表中所有的桶,但是没有找到空桶,则认为哈希表已满,此时需要进行哈希表扩容等操作才能继续向其中添加元素。

      同时,在哈希表中查询某个元素时,也需要采用类似的方式来进行查找。具体而言,查询时从哈希函数计算得到的初始桶 h 开始,逐个检查当前桶、其下一项、再下去的下一项等等直到查询到的元素或者一个空桶为止。

需要注意,线性探测法虽然简单,但是容易出现堆积和聚集的问题,导致哈希表的效率急剧降低。因此,在实际应用中,如果采用了线性探测法作为哈希表存储冲突处理的方法,就需要根据具体情况进行调整,以避免这种问题的发生。

  1. 双散列函数法
      双散列函数法也是一种常见的开放地址哈希表冲突解决方法,它通过构造两个不同的哈希函数,分别计算出可能的插入位置,以此来避免冲突,并且添加新元素时按照一个固定的步长,在空桶之间线性查找下一个可以使用的位置。
      具体来说,对于双散列函数法,假设我们有两个哈希函数 h1、h2,在哈希表中查找第 i 个关键字时,计算其哈希值有两种方式:

    1. 计算第一层哈希:h1(key)=ih1​(key)=i
      如果第 h1(i) 个桶为空,则将关键字存储在该桶中。否则执行第二步;

    2. 计算第二层哈希: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 的哈希值相同,它们属于同一个桶,因此需要将它们分别插入到同一个链表中。最终,我们可以得到下面这张包含所有关键字的哈希表表示:

01234
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博客…...

熵值法综合评价分析流程

熵值法综合评价分析流程 一、案例背景 当前有一份数据,是各品牌车各个维度的得分情况,现在想要使用熵值法进行综合评价,得到各品牌车的综合得分,从而进行车型优劣对比,为消费者提供购车依据。 数据如下(数…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

python打卡day49

知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...