[数据结构] 哈希结构的哈希冲突解决哈希冲突

news2024/9/20 6:38:20

标题:[C++] 哈希结构的哈希冲突 && 解决哈希冲突

@水墨不写bug



目录

一、引言

        1.哈希

        2.哈希冲突

        3.哈希函数

 二、解决哈希冲突

1.闭散列

 I,线性探测

II,二次探测

2.开散列


正文开始:

一、引言

        哈希表是一种非常实用而且好用的关联式容器,如果你刷过不少题,一定会惊叹哈希竟然能解决如此多的实际问题。

        但是哈希表令人头疼的问题是哈希冲突的问题。在具体讲解之前,我们先铺垫引入几个概念:哈希,哈希函数,哈希冲突。

        1.哈希

         哈希结构最明显的特点是高效。在以往的顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(log2 N),搜索的效率取决于搜索过程中元素的比较次数。

最优的搜索方法:不经过任何比较,一次直接从表中得到要搜索的元素。

        如果存在一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码(key)之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。

        当我们向该结构中:

插入元素的时候:根据插入元素的关键码,根据这个关键码来通过某种映射关系来得到哈希表中对应的存储位置,然后将这个元素存入哈希表的对应位置。

搜索元素的时候:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在哈希表中按照此位置进行查找,若关键码相等,则搜索成功。

        这种存储结构和方法统称为哈希

        哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表).

        2.哈希冲突

        我们可以设计一个简单的哈希表:10个位置,哈希函数也是非常简单的除留取余(插入元素除以表的大小,就通过哈希函数得到了这个值应该在表中存储的位置):

        用该方法进行搜索可以一次找到存储对应值的位置,因此搜索的速度比较快。

但是,如果向上面这样的哈希表中插入14呢?

        我们发现14的位置被4占据了,这就是哈希冲突。

        即:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

        把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”.

        3.哈希函数

 引起哈希冲突的一个原因可能是:哈希函数设计不够合理。

哈希函数设计原则:

        1.哈希函数的定义域必须包括需要存储的全部关键码,同时如果散列表允许有m个地址时,其值域必须在0到m-1之间。

        2.哈希函数计算出来的地址能尽可能的均匀分布在整个空间中。

        3.哈希函数应该比较简单

         我们需要了解一下常见的哈希函数的设计方法:

1. 直接定址法

        取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B

        优点:简单、均匀、一般不会出现哈希冲突

        缺点:需要事先知道关键字的分布情况

        使用场景:适合查找比较小且连续的情况

2. 除留余数法.

        设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址.

        优点:适用情况广泛

        缺点:会出现哈希冲突,需要解决哈希冲突的问题

 二、解决哈希冲突

        哈希冲突的解决方法常用的有两种:闭散列与开散列。

1.闭散列

         闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。

        寻找下一个“空位置”也有多种方法,这里介绍常见的两种:线性探测,二次探测。

 I,线性探测

         在上面的例子中,我们想要插入14,本来14经过哈希函数计算得到的位置是4,但是4这个位置已经被占据了。

        线性探测就是:从发生冲突的位置开始,一个一个向后探测,直到寻找到下一个空位置为止。

        a.插入

        首先通过哈希函数获取待插入元素在哈希表中的位置。 如果该位置中没有元素则直接插入新元素;如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素:

        b.删除

        采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他元素的搜索。

        比如:删除元素4,如果直接删除掉,14查找起来可能会受影响。因此线性探测采用标记的伪删除法来删除一个元素。

        我们可以通过一个标记状态的变量来表示哈希表内的数据的状态:存在,删除,空(EXIST,DELETE,EMPTY):

enum STATE
{
    EXIST,
    DELETE,
    EMPTY
}    

        在封装哈希表中每一个数据的类型时,在每个数据结构体内加入一个表示状态的变量即可。对于一个哈希表的位置,如果没有元素插入过,状态为EMPTY;

        如果存在元素,状态为EXIST;

        如果原来存在元素,但是之后删除了,状态为DELETE;

不同的状态对于将来查找(find)的处理会有影响。 

II,二次探测

         通过了解上面的线性探测,你自然也会发现线性探测的困难:

        产生冲突的数据堆积在一块,这与其一个一个向下找空位置有关系,找空位置的方式就是挨着往后逐个去找.

        二次探测的找下一个空位置的方法就大不相同了:二次探测向下找的方式是依次加上位置差的平方:

H_i = (H_0 + i^2 )% m 或者H_i = (H_0 - i^2 )% m

        其中:i = 1,2,3…, H_0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小。

        对于上面的例子,如果使用二次探测,插入的过程:

插入 44 的过程:
    1.44 的初始哈希值是  14 % 10 = 4 ,但是位置 4 已经被占用了。
    2.触发二次探测,从  i = 1  开始。对于  i = 1 ,探测位置是:(4 + 1^2) % 10 = 5 但位置 5 也被占用了。
    3.继续探测, i = 2  时,探测位置是:(4 + 2^2) % 10 = 8

位置 8 是空的,所以 14 被插入到位置 8。

        对于闭散列而言,哈希表是需要扩容的,因为我们每次插入的时候都需要保证哈希表有空余的位置,所以我们需要一个判断哈希表内数据 装满程度的标志因子:载荷因子

        载荷因子记为a,a越大,表明填入表中的数据越多,产生哈希冲突的可能就越大。反之则相反。

        对于开放定址法,载荷因子需要严格控制在0.7-0.8以下。当载荷因子接近这个值时,就需要扩容。

2.开散列

         开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中:

        

        当插入14时,对4这个位置的链表头插即可:

 

 以上是哈希结构解决哈希冲突的方法。


完~

未经作者同意禁止转载 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

移动UI:分类列表页、筛选页的设计揭秘。

移动UI的列表页设计需要考虑用户体验和界面美观性&#xff0c;以下是一些建议的设计要点&#xff1a; 1. 列表项的展示&#xff1a; 列表页应该清晰地展示各个列表项&#xff0c;包括标题、副标题、缩略图等内容&#xff0c;以便用户快速浏览和识别。可以使用卡片式布局或者简…

计算机毕业设计选题推荐-班级管理系统-教务管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

多云架构下大模型训练的存储稳定性探索

一、多云架构与大模型训练的融合 &#xff08;一&#xff09;多云架构的优势与挑战 多云架构为大模型训练带来了诸多优势。首先&#xff0c;资源灵活性显著提高&#xff0c;不同的云平台可以提供不同类型的计算资源和存储服务&#xff0c;满足大模型训练在不同阶段的需求。例…

机器学习之监督学习(四)决策树和随机森林

机器学习之监督学习&#xff08;四&#xff09;决策树和随机森林 0. 文章传送1. 决策树 Decision Tree案例引入构建过程 0. 文章传送 机器学习之监督学习&#xff08;一&#xff09;线性回归、多项式回归、算法优化[巨详细笔记] 机器学习之监督学习&#xff08;二&#xff09;…

YOLOv8改进实战 | 注意力篇 | 引入ICCV2023顶会LSKNet:大选择性卷积注意力模块LSKA,助力小目标检测

YOLOv8专栏导航:点击此处跳转 前言 YOLOv8 是由 YOLOv5 的发布者 Ultralytics 发布的最新版本的 YOLO。它可用于对象检测、分割、分类任务以及大型数据集的学习,并且可以在包括 CPU 和 GPU 在内的各种硬件上执行。 YOLOv8 是一种尖端的、最先进的 (SOTA) 模型,它建立在以前…

Leetcode JAVA刷刷站(113)路径总和 ||

一、题目概述 二、思路方向 为了找出从根节点到叶子节点路径总和等于给定目标和的所有路径&#xff0c;我们可以使用深度优先搜索&#xff08;DFS&#xff09;的方法。在遍历过程中&#xff0c;我们维护一个当前路径的和以及一个列表来存储当前路径的节点值。当我们到达一个叶…

HarmonyOS云端开发(二)

文章目录 登录认证服务以及云数据库使用一创建登录注册页面二、开启认证服务二、创建数据表1.导出数据表2.使用表 进行增删改查3.查看云数据库 登录认证服务以及云数据库使用 云端开发不需要存储token,由提供的API统一验证&#xff0c;假设未登录则跳转登录页&#xff0c;已登…

uniapp,vite整合windicss

官方文档&#xff1a;https://weapp-tw.icebreaker.top/docs/quick-start/frameworks/hbuilderx 安装&#xff1a; npm i -D tailwindcss postcss autoprefixer # 初始化 tailwind.config.js 文件 npx tailwindcss initnpm i -D weapp-tailwindcss# 假如 tailwindcss 在 weap…

nginx 新建一个 PC web 站点

注意&#xff1a;进行实例之前必须完成nginx的源码编译。&#xff08;阅读往期文章完成步骤&#xff09; 1.编辑nginx的配置文件&#xff0c;修改内容 [rootlocalhost ~]# vim /usr/local/nginx/conf/nginx.conf 2.创建新目录/usr/local/nginx/conf.d/&#xff0c;编辑新文件…

JavaScript (输出,语句,语法)

目录 JavaScript 输出 使用window.alert() 写入警示框 使用document.write() 写入HTMl输入 使用 innerHTML 写入html元素 使用console.log&#xff08;&#xff09;写入 浏览器控制台 JavaScript 语句 实例 语句组成 分号 关键字 JavaScript 语法 JavaScript 标识符 …

【Hadoop|MapReduce篇】MapReduce概述

1. MapReduce定义 MapReduce是一个分布式运算程序的编程框架&#xff0c;是用户开发“基于Hadoop的数据分析应用”的核心框架。 MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序&#xff0c;并发运行在一个Hadoop集群上。 2. Map…

项目——负载均衡OJ

项目要实现的一个整体的功能&#xff1a; 编写一个在线OJ网络服务器,只实现类似 leetcode 的题目列表在线编程功能 项目宏观结构: Oj服务器在收到提交的代码时&#xff0c;把代码负载均衡的选择发送给其他几个编译与运行服务器去编译运行代码&#xff0c;判断代码的编译运行结…

springboot+vue+mybatis计算机毕业设计气象数据分析与可视化系统+PPT+论文+讲解+售后

随着互联网技术不断地发展&#xff0c;网络与大数据成为了人们生活的一部分&#xff0c;而气象数据分析与可视化系统 作为网上应用的一个全新的体现&#xff0c;由于其特有的便捷性&#xff0c;已经被人们所接受。目前主流的气象数据分析与可视化系统 服务不仅不明确并且管理…

滑动窗口系列(同向双指针)/9.7

新的解题思路 一、三数之和的多种可能 给定一个整数数组 arr &#xff0c;以及一个整数 target 作为目标值&#xff0c;返回满足 i < j < k 且 arr[i] arr[j] arr[k] target 的元组 i, j, k 的数量。 由于结果会非常大&#xff0c;请返回 109 7 的模。 输入&…

AMEYA360:村田量产用于汽车市场的高可靠性0603M铜电极负温度系数NTC热敏电阻

株式会社村田制作所开发了0603M尺寸(0.60.30.3mm)铜电极负温度系数(NTC)热敏电阻&#xff0c;型号分别是“NCU03XH103F6SRL”和“NCU03XH103F60RL”&#xff0c;该新品扩充了NCU系列的产品尺寸阵容&#xff0c;满足了汽车市场应用中电路板的高密度化和小型化、以及对电子部件的…

AF路由模式组网部署

实验拓扑 防火墙基本配置 接口配置 eth1 eth2 eth3 路由配置 地址转换配置 放通策略 1. 出口申请了主电信、备联通两条外网线路&#xff08;均为 50M 带宽&#xff09;。 2. 内网有 web 服务器linux 172.16.3.100运行 http 服务&#xff0c;内外网用户通过 出口路由器…

Kubernetes 1.25 containerd 环境部署 SuperMap iManager

超图官网目提供的Kubernetes 版本为 1.20 版本&#xff0c;容器运行时为 docker 本次部署使用已有的 Kubernetes 1.25 版本集群&#xff0c;容器运行时为 containerd Kubernetes &#xff0c;containerd 部署请自行了解&#xff0c;本次不做介绍&#xff0c;下面介绍在此环境上…

MATLAB绘图基础5:MATLAB数据导入

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 5.MATLAB数据导入 5.1 从CSV文件读取数据 C S V {\rm CSV} CSV文件是一种纯文本文件&#xff0c;文件中的数据以逗号为分隔符进行字段分隔&#xff0c;每一行数据代表一条记录&#xff0c;每…

通信工程学习:什么是AB地址总线、DB数据总线、CD控制总线

AB地址总线、DB数据总线、CD控制总线 在计算机体系结构中&#xff0c;总线&#xff08;Bus&#xff09;是一种用于在计算机内部各个组件之间传输信息的物理通道。其中&#xff0c;AB地址总线、DB数据总线和CD控制总线是计算机总线系统中非常重要的三个组成部分&#xff0c;它们…

机器学习-神经网络:循环神经网络(RNN)详解

引言 在当今人工智能(AI)和深度学习(DL)领域,循环神经网络(RNN)作为一种专门处理序列数据的模型,具有不可忽视的重要性。RNN 的设计目标是模拟和处理序列中的时间依赖关系,使其成为许多应用场景的理想选择,如自然语言处理(NLP)、时间序列预测和语音识别等。它不仅…