[数据结构] 哈希结构的哈希冲突解决哈希冲突
标题:[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这个位置的链表头插即可:

以上是哈希结构解决哈希冲突的方法。
完~
未经作者同意禁止转载
相关文章:
[数据结构] 哈希结构的哈希冲突解决哈希冲突
标题:[C] 哈希结构的哈希冲突 && 解决哈希冲突 水墨不写bug 目录 一、引言 1.哈希 2.哈希冲突 3.哈希函数 二、解决哈希冲突 1.闭散列 I,线性探测 II,二次探测 2.开散列 正文开始: 一、引言 哈希表是一种非常实用而…...
Wimdows使用Appium IOS自动化
启动appium服务器: appium -a 127.0.0.1 -p 4724 配置 { "platformName": "iOS", "appium:platformVersion": "16.5.1", "appium:deviceName": "(★StatTrak™) |午夜黑(崭新出厂&#…...
C语言深度剖析--不定期更新的第四弹
哈哈哈哈哈哈,今天一天两更! void关键字 void关键字不能用来定义变量,原因是void本身就被编译器解释为空类型,编译器强制地不允许定义变量 定义变量的本质是:开辟空间 而void 作为空类型,理论上不应该开…...
【手撕数据结构】八大排序神功(上)
目录 冒泡排序【有点拉胯】动图演示:思路解析单趟算法图解代码详解性能优化复杂度分析 直接插入排序【还阔以】动图演示思路解析代码分析与讲解复杂度分析 希尔排序【有点强】动图演示思路讲解排序过程总览代码分析讲解复杂度分析 堆排序【太有石粒啦】动图演示堆的概念与结构向…...
【2024高教社杯全国大学生数学建模竞赛】B题模型建立求解
目录 1问题重述1.1问题背景1.2研究意义1.3具体问题 2总体分析3模型假设4符号说明(等四问全部更新完再写)5模型的建立与求解5.1问题一模型的建立与求解5.1.1问题的具体分析5.1.2模型的准备 目前B题第一问的详细求解过程以及对应论文部分已经完成ÿ…...
OpenHarmony鸿蒙开发( Beta5.0)智能手表应用开发实践
样例简介 本项目是基于BearPi套件开发的智能儿童手表系统,该系统通过与GSM模块(型号:SIM808)的通信来实现通话和定位功能。 智能儿童手表系统可以通过云和手机建立连接,同步时间和获取天气信息,通过手机下…...
共享单车轨迹数据分析:以厦门市共享单车数据为例(一)
共享单车数据作为交通大数据的一个重要组成部分,在现代城市交通管理和规划中发挥着越来越重要的作用。通过对共享单车的数据进行深入分析,城市管理者和规划者能够获得大量有价值的洞察,这些洞察不仅有助于了解城市居民的日常出行模式…...
SprinBoot+Vue在线商城微信小程序的设计与实现
目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平…...
4--SpringBootWeb-请求响应
目录 postman 1.简单参数 请求参数名与形参变量名一致时 请求参数名与形参变量名不一致时 2.实体参数 简单实体对象 复杂实体对象 3.数组集合参数 数组 集合 4.日期参数 5.JSON参数 6.路径参数 1 2 postman Postman值一款功能强大的网页调试与发送网页HTTP请求的…...
电脑点击关机之后,又自动重启开机了。根本就关不了?
前言 有个小姐姐说,她家的电脑好生奇怪:点击【关机】按钮之后,电脑提示【正在关机】,过了几秒,电脑又自动开机了…… 好家伙!也就是说关机和重启根本就没区别,电脑完全无法断电。 最后忍无可…...
强化网络安全:通过802.1X协议保障远程接入设备安全认证
随着远程办公和移动设备的普及,企业网络面临着前所未有的安全挑战。为了确保网络的安全性,同时提供无缝的用户体验,我们的 ASP 身份认证平台引入了先进的 802.1X 认证协议,确保只有经过认证的设备才能接入您的网络。本文档将详细介…...
链动2+1模式AI智能名片S2B2C商城小程序源码在社群商业价值构建中的应用探索
摘要:在数字经济浪潮的推动下,社群作为商业生态的核心组成部分,其商业价值正以前所未有的速度增长。本文深入探讨了如何通过“链动21模式AI智能名片S2B2C商城小程序源码”这一前沿技术工具,深度挖掘并优化社群的商业价值。通过详细…...
基于SpringBoot+Vue+MySQL的校园周边美食探索及分享平台
系统背景 在当今数字化时代,校园生活正日益融入信息技术的浪潮之中,学生们对于便捷、高效且富有趣味性的生活方式有着越来越高的追求。特别是在饮食文化方面,随着校园周边餐饮业态的日益丰富,学生们渴望一个能够集美食探索、分享与…...
“设计模式双剑合璧:工厂模式与策略模式在支付系统中的完美结合”
工厂模式(Factory Pattern)和策略模式(Strategy Pattern)都是常见的设计模式,但它们解决的问题和应用场景不同。下面是它们的区别: 1. 目的不同: 工厂模式(Factory Pattern…...
第二百一十九节 JPA 教程 - JPA 字段映射示例
JPA 教程 - JPA 字段映射示例 当将 Java bean 字段映射到数据库列时,我们可以选择标记字段,标记 getter 方法并标记两者。 标记字段 以下代码来自 Professor.java。 它显示如何将主键列标记为 Java bean 字段标识。 package cn.w3cschool.common; im…...
目标检测-YOLOv6
YOLOv6 YOLOv6 是 YOLO 系列的一个新版本,相比 YOLOv5 进行了大量的优化与改进。YOLOv6 的设计目标是在提高模型检测精度的同时,进一步优化速度和效率,特别是在推理速度和部署便捷性方面。它采用了更先进的网络架构和优化技巧,在…...
Java面向对象与多态
目录 Java面向对象与多态 多态介绍 形成多态的前提 多态下成员访问的特点 成员变量 成员方法 访问特点总结 多态对比普通继承 普通继承优点与缺点 多态优点与缺点 向上转型与向下转型 向下转型存在的问题 多态接口练习 Java面向对象与多态 多态介绍 在前面学习到…...
redis分布式锁和lua脚本
业务场景:多个线程对共同资源的访问:库存超卖/用户重复下单的原因 解决方法一:利用jvm内置锁,将非原子性操作变成原子性操作 Synchronized锁的是对象,对象必须是单例的。锁的是this,代表当前所在的类,这个…...
项目实战 ---- 商用落地视频搜索系统(5)---service层核心
目录 背景 向下service 层 描述 功能 代码实现 核心阐述 向上service层 描述 功能 代码实现 核心阐述 背景 之前的 1-4 重点在介绍系统的实现架构,录入数据的组织形式,存储模式,search 方式,以及后期算法等。重点都是聚焦在后端。现在来看,基本的后端实现我们…...
Win32远线程注入
远线程注入 远线程(RemoteThread)注入是指一个进程在另一个进程中创建线程的技术,这是一种很经典的DLL注入技术。 虽然比较古老,但是很实用。通过远线程注入,再配合api函数的hook技术,可以实现很多有意思的功能。 实现远线程注入…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...


b.删除