当前位置: 首页 > 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博客…...

熵值法综合评价分析流程

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

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...