哈希表冲突及处理冲突的方法(含例子)

2023-11-05

一、哈希函数和哈希冲突的基本概念


1.哈希函数:

哈希法又称散列法、杂凑法以及关键字地址计算法等,相应的表成为哈希表。

基本思想:首先在元素的关键字K和元素的位置P之间建立一个对应关系f,使得P=f(K),其中f成为哈希函数。

创建哈希表时,把关键字K的元素直接存入地址为f(K)的单元;

查找关键字K的元素时利用哈希函数计算出该元素的存储位置P=f(K).

2.哈希冲突:

当关键字集合很大时,关键字值不同的元素可能会映像到哈希表的同一地址上,即K1!=K2,但f(K1)=f(K2),这种现象称为hash冲突,实际中冲突是不可避免的,只能通过改进哈希函数的性能来减少冲突。

二、哈希函数的构造方法 


哈希函数的构造原则是:函数本身便于计算、计算出来的地址分布均匀(即对任意K,f(K)对应不同地址的概率相等)。

1.数字分析法:

可以从关键如果事先知道关键字集合,并且每个关键字的位数比哈希表的地址码位数多时,可以从关键字中选出分布较均匀的若干位,构成哈希地址。

例如,有80个记录,关键字为8位十进制整数d1d2d3…d7d8,如哈希表长取100,则哈希表的地址空间为:00~99。

假设经过分析,各关键字中 d4和d7的取值分布较均匀,则哈希函数为:h(key)=h(d1d2d3…d7d8)=d4d7。例如,h(81346532)=43,h(81301367)=06。

相反,假设经过分析,各关键字中 d1和d8的取值分布极不均匀, d1 都等于5,d8 都等于2,此时,如果哈希函数为:h(key)=h(d1d2d3…d7d8)=d1d8,

则所有关键字的地址码都是52,显然不可取。

2.平方取中法:

当无法确定关键字中哪几位分布较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。

这是因为:平方后中间几位和关键字中每一位都相关,故不同关键字会以较高的概率产生不同的哈希地址。

例:我们把英文字母在字母表中的位置序号作为该英文字母的内部编码。例如K的内部编码为11,E的内部编码为05,Y的内部编码为25,A的内部编码为01, B的内部编码为02。

由此组成关键字“KEYA”的内部代码为11052501,同理我们可以得到关键字“KYAB”、“AKEY”、“BKEY”的内部编码。之后对关键字进行平方运算后,取出第7到第9位作为该关键字哈希地址,如图8.23所示。

关键字     内部编码       内部编码的平方值           H(k)关键字的哈希地址

KEYA      11050201      122157778355001                      778
KYAB      11250102      126564795010404                      795
AKEY      01110525       001233265775625                     265

BKEY      02110525       004454315775625                     315

 3.分段叠加法:

这种方法是按哈希表地址位数将关键字分成位数相等的几部分(最后一部分可以较短),然后将这几部分相加,舍弃最高进位后的结果就是该关键字的哈希地址。

具体方法有折叠法与移位法。移位法是将分割后的每部分低位对齐相加,折叠法是从一端向另一端沿分割界来回折叠(奇数段为正序,偶数段为倒序),然后将各段相加。  

例如:key=12360324711202065,哈希表长度为1000,则应把关键字分成4位一段,在此舍去最低的两位65,分别进行移位叠加和折叠叠加,求得哈希地址为105和907 

(a)移位叠加              (b) 折叠叠加
       1   2   3                    1   2   3
       6   0   3                    3   0   6
       2   4   7                    2   4   7
       1   1   2                    2   1   1
       0   2   0                    0   2   0
——————               ——————

  1   1   0   5                    9   0   7

4.除留余数法:

假设哈希表长为m,p为小于等于m的最大素数,则哈希函数为 h(k)=k  %  p ,其中%为模p取余运算。

例如,已知待散列元素为(18,75,60,43,54,90,46),表长m=10,p=7,则有h(18)=18 % 7=4    h(75)=75 % 7=5    h(60)=60 % 7=4   h(43)=43 % 7=1    h(54)=54 % 7=5    h(90)=90 % 7=6   h(46)=46 % 7=4此时冲突较多。为减少冲突,可取较大的m值和p值,如m=p=13,结果如下:h(18)=18 % 13=5    h(75)=75 % 13=10    h(60)=60 % 13=8    h(43)=43 % 13=4    h(54)=54 % 13=2    h(90)=90 % 13=12   h(46)=46 % 13=7

三、处理冲突的方法


 1.开放定址法(再散列法): 

基本思想:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。 这种方法有一个通用的再散列函数形式: 

            Hi=(H(key)+di)% m   i=1,2,…,n

其中H(key)为哈希函数,m 为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。 

1.线性探测再散列:

dii=1,2,3,…,m-1         冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

2.二次探测再散列:

di=12,-12,22,-22,…,k2,-k2    ( k<=m/2 )         冲突发生时,在表的左右进行跳跃式探测,比较灵活。

3.伪随机探测再散列:

di=伪随机数序列。  具体实现时,应建立一个伪随机数发生器,(如i=(i+p) % m),并给定一个随机数做起点。

4.  示例:

已知哈希表长度m=11,哈希函数为:H(key)= key  %  11,则H(47)=3,H(26)=4,H(60)=5,

假设下一个关键字为69,则H(69)=3,与47冲突。

 a): 如果用线性探测再散列处理冲突,下一个哈希地址为H1=(3 + 1)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 + 2)% 11 = 5,还是冲突,继续找下一个哈希地址为H3=(3 + 3)% 11 = 6,此时不再冲突,将69填入5号单元。

 0     1     2     3     4     5     6     7     8     9     10

                     47   26   60   69

b): 如果用二次探测再散列处理冲突,下一个哈希地址为H1=(3 + 12)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 - 12)% 11 = 2,此时不再冲突,将69填入2号单元。

     0     1     2     3     4     5     6     7     8     9     10

                  69   47   26  60      

 c): 如果用伪随机探测再散列处理冲突,且伪随机数序列为:2,5,9,……..,则下一个哈希地址为H1=(3 + 2)% 11 = 5,仍然冲突,再找下一个哈希地址为H2=(3 + 5)% 11 = 8,此时不再冲突,将69填入8号单元。

 0     1     2     3     4     5     6     7     8     9     10

                  47   26  60                  69

 

2.再哈希法:

这种方法是同时构造多个不同的哈希函数: Hi=RH1(key)  i=1,2,…,k

当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

3.拉链法(HashMap的冲突处理方式):

基本思想: 将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

例如:  已知一组关键字(32,40,36,53,16,46,71,27,42,24,49,64),哈希表长度为13,哈希函数为:H(key)= key % 13,则用链地址法处理冲突的结果如图所示:

位置    Entry 
        0
        1  -->  40 --> 27 --> 53
        2
        3  -->  16 --> 42
        4
        5
        6  -->  32 --> 71

        7
        8
        9
        10 -->  36 --> 49
        11 -->  24
        12 -->  64
        
 本例的平均查找长度 ASL=(1*7+2*4+3*1)/13=1.38

 

4.建立公共溢出区:

这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表
————————————————
版权声明:本文为CSDN博主「Hello_GY」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40803710/article/details/80945617

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

哈希表冲突及处理冲突的方法(含例子) 的相关文章

随机推荐

  • Java中类和对象的关系

    一 基本概念 1 类 类是一个模板 它描述一类对象的行为和状态 比如一张汽车设计图纸 2 对象 对象表示现实世界中一个具体的事物 对象是类的一个实例 有状态和行为 例如 一条狗是一个对象 它的状态有 颜色 名字 品种 行为有 摇尾巴 叫 吃
  • 闲来无事搭个代理池子

    基于ProxyPool创建Proxifier代理 如题目所见 闲来无事在做测试时发现被某网站封了IP 为防止再被封掉 因此有了这篇文章和搭建过程 0x01 安装redis服务 ubuntu16 04 apt get install redi
  • FISCO BCOS(十五)——— Windows下的go环境配置及beego环境配置并解决bee run报错问题

    1 下载地址 https golang google cn dl 2 双击打开下载的文件 一路按照默认点击下一步 安装位置可选 默认安装在c盘 3 go环境配置 很重要的 在系统变量名中新建变量名 GOPATH 变量值 E go space
  • React 合成事件

    文章借鉴 pingan8787 React合成事件 和 React合成事件官方文档 React 合成事件 一 概念介绍 React合成事件是React 模拟原生DOM事件所有能力 的一个事件对象 根据 W3C规范 来定义合成事件 兼容所有浏
  • UE4大数据可视化教程(21)——大屏云渲染通用像素流解决方案

    目录 项目打包前操作 复制信令服务器文件 快捷打开信令服务和启动项目 替换项目
  • 虚拟机中的Windows重置系统密码

    概述 相信大家不管是在企业还是个人都或多或少接触过虚拟机 在安装操作系统的时候 有的需要密码 而且默认有时总是提示需要更改密码 导致忘记密码 但又不能重装操作系统也不能回退就很烦 这里本博主今天突然想到这个问题就出一篇文章 虽然我没有忘记过
  • 软件工程基础知识复习宝典

    前言 此文档为个人大学时期应付期末考试时自行总结 用于理解并背诵相应的基本概念 一些计算和画图之类的内容需要结合书本例题进行复习 多做习题深刻掌握 中间大标题为老师给出的考纲中建议每一章需要掌握的一些知识点 如若需要doc文档版打印复习 请
  • [C++11]弱引用智能指针weak_ptr初始化和相关的操作函数

    弱引用智能指针 std weak ptr 可以看做是 shared ptr 的助手 它不管理 shared ptr 内部的指针 std weak ptr 没有重载操作符 和 gt 因为它不共享指针 不能操作资源 所以它的构造不会增加引用计数
  • 【YOLOv5】1.搭建Pycharm+Python+yolov5环境

    目录 一 安装Python 二 安装PyCharm 三 创建项目和虚拟环境 四 下载YOLOv5和依赖库 五 配置Pytorch 六 检验YOLOv5环境 一 安装Python 1 Python官方下载网址 Download Python
  • 解决echarts报错Cannot read properties of null (reading ‘getAttribute‘)

    前言 最近在写 echarts 的时候碰到了这么一个报错 如下图 造成报错的原因是因为 echarts 的图形容器还未生成就对其进行了初始化 下面几种方法是经本人自测最有效的解决方案 报错截图 解决方案 1 this nextTick 该方
  • c++ primer 中的文本查询示例

    前言 有个牛人叫bnu chenshuo 发微博说 回复 TheRealBo 学生编程练习 把 Unix 的命令行小工具用C C 实现一遍 wc cat ls cp grep sort uniq nc head tail hexdump 把
  • 电源正负极防反接保护的几种实现方案!

    电源防反接 应该是很多电路场景下都会采取到此系列得设计 前几日 小白在做单板验证时 在接上假电池然后电源供电时 一不小心将假电池的正负极与供电电源的输入输出接反了 导致单板烧坏 瞬间一缕青烟飘荡在我的座位上 由于我们的产品用的是真电池 所以
  • Ubuntu设置定时重启

    1 安装 更新 cron 安装crontab sudo apt get install cron 更新命令 sudo apt get update 2 配置cron定时任务 sudo nano etc crontab root reboot
  • c语言汇编混合编译不了,是用c语言和汇编混合编的程序,在keil里编译时出现C51 FATAL-ERROR -...

    满意答案 qun260 推荐于 2018 05 13 采纳率 59 等级 8 已帮助 312人 程序问题 LL SEGMENT CODE 在程序存储区中定义段 PUBLIC LED 声明函数 FLAG DATA 20H DPFLAG DAT
  • 几十行代码 轻松实现人脸识别、人脸检测

    人脸识别最近几年变得很火 技术也已经相对成熟 应用场景也很多 下面将介绍简单几种实现人脸检测 人脸识别的简单方法 我博客中也写了几篇有人脸识别应用的文章 现在分类总结下 人脸识别技术介绍已经近况以及应用 https blog csdn ne
  • Java8 利用Lambda处理List集合循环给另外一个List赋值过滤处理

    1 利用stream forEach 循环处理List List
  • mysql查询作为是否有连续以及是否有人

    有张表t1 表结构如图 0 表示座位没人 1表示座位有人 查询出座位是连续的且没有人的seat id SELECT DISTINCT a seat id from t1 as a t1 AS b WHERE a free 1 AND b f
  • golang base64解码编码实现

    golang base64解码编码实现 golang base64解码编码实现 go实现base64解码编码非常简单 知道调用go安装时自带的encoding base64就可以了 package main import encoding
  • ByteHouse 与 Apache Airflow 的数据管理流程

    动手点关注 干货不迷路 Apache Airflow 与 ByteHouse 相结合 为管理和执行数据流程提供了强大而高效的解决方案 本文突出了使用 Apache Airflow 与 ByteHouse 的主要优势和特点 展示如何简化数据工
  • 哈希表冲突及处理冲突的方法(含例子)

    一 哈希函数和哈希冲突的基本概念 1 哈希函数 哈希法又称散列法 杂凑法以及关键字地址计算法等 相应的表成为哈希表 基本思想 首先在元素的关键字K和元素的位置P之间建立一个对应关系f 使得P f K 其中f成为哈希函数 创建哈希表时 把关键