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

数据结构 散列表—— 冲突解决方法

冲突解决方法

尽管通过合理设计散列函数能大幅减少冲突,但冲突仍无法完全避免。冲突解决方法的核心是:当多个关键字通过散列函数映射到同一散列地址时,为后续关键字找到新的空闲存储位置,同时保证后续查找时能准确找到这些关键字。常用的冲突解决方法可分为“开放定址法”和“链地址法”两大类,此外还有再散列法、公共溢出区法等辅助方式。

1. 开放定址法

开放定址法的核心思路是:当关键字keykeykey的初始散列地址H0=H(key)H_0 = H(key)H0=H(key)发生冲突时,在散列表内部按照一定规则依次探测其他地址,直到找到空闲地址或确认表满。探测地址的序列可表示为:
Hi=(H(key)+di)%m(i=1,2,...,m−1)H_i = (H(key) + d_i) \% m \quad (i=1,2,...,m-1)Hi=(H(key)+di)%m(i=1,2,...,m1)
其中mmm是散列表容量,did_idi是探测增量(不同探测规则对应不同的did_idi),且所有探测地址均在0∼m−10 \sim m-10m1范围内(避免越界)。

(1)线性探测法
线性探测法的探测增量为线性递增序列,即di=id_i = idi=ii=1,2,...,m−1i=1,2,...,m-1i=1,2,...,m1),探测序列为:
H1=(H0+1)%m,H2=(H0+2)%m,...H_1 = (H_0 + 1) \% m, \quad H_2 = (H_0 + 2) \% m, \quad ...H1=(H0+1)%m,H2=(H0+2)%m,...

例如,散列表容量m=10m=10m=10,散列函数H(key)=key%10H(key)=key\%10H(key)=key%10

  • 关键字key1=25key_1=25key1=25,初始地址H0=5H_0=5H0=5(空闲),存入地址5;
  • 关键字key2=35key_2=35key2=35,初始地址H0=5H_0=5H0=5(冲突),探测H1=6H_1=6H1=6(空闲),存入地址6;
  • 关键字key3=45key_3=45key3=45,初始地址H0=5H_0=5H0=5(冲突),探测H1=6H_1=6H1=6(冲突),探测H2=7H_2=7H2=7(空闲),存入地址7。

这种方法的优点是计算简单,缺点是容易产生“聚集现象”——多个冲突的关键字会连续占据一段地址(如25、35、45占据5、6、7),后续关键字即使初始地址不冲突,也可能被这段连续地址阻挡,增加冲突概率。

(2)二次探测法
二次探测法通过非线性增量改善聚集问题,探测增量为二次函数序列,常用di=±i2d_i = \pm i^2di=±i2i=1,2,...,ki=1,2,...,ki=1,2,...,kk≤m/2k \leq m/2km/2),探测序列为:
H1=(H0+12)%m,H2=(H0−12)%m,H3=(H0+22)%m,H4=(H0−22)%m,...H_1 = (H_0 + 1^2) \% m, \quad H_2 = (H_0 - 1^2) \% m, \quad H_3 = (H_0 + 2^2) \% m, \quad H_4 = (H_0 - 2^2) \% m, \quad ...H1=(H0+12)%m,H2=(H012)%m,H3=(H0+22)%m,H4=(H022)%m,...

仍以m=10m=10m=10H0=5H_0=5H0=5为例:

  • 冲突时先探测5+1=65+1=65+1=6,再探测5−1=45-1=451=4,接着探测5+4=95+4=95+4=9,再探测5−4=15-4=154=1,避免了线性探测的连续聚集。

二次探测法能有效减少聚集,但需注意:当mmm为形如4k+34k+34k+3的质数时,才能保证探测到散列表的所有地址(避免遗漏空闲位置)。

2. 链地址法

链地址法(又称拉链法)的核心思路是:将散列表的每个地址作为“链表头指针”,同一散列地址的关键字(称为“同义词”)存储在该地址对应的链表中(称为“同义词链表”)。当发生冲突时,无需在散列表内探测其他地址,只需将新关键字插入对应链表的头部或尾部即可。

例如,散列表容量m=10m=10m=10,散列函数H(key)=key%10H(key)=key\%10H(key)=key%10,存储关键字25、35、45、15的过程如下:

  • 关键字25:H0=5H_0=5H0=5,地址5的链表为空,创建链表节点存入25;
  • 关键字35:H0=5H_0=5H0=5,地址5的链表非空,将35插入链表尾部(或头部);
  • 关键字45、15:同理,均插入地址5的链表,最终该链表包含25、35、45、15四个节点。

链地址法的优点很明显:

  • 无聚集现象:同义词仅在同一链表内存储,不影响其他地址;
  • 删除方便:只需删除链表中的对应节点,无需调整其他关键字位置;
  • 空间利用率高:散列表仅存储链表头指针,链表长度可随关键字数量动态变化(无需预设过大的散列表容量)。

缺点是需额外存储链表指针,且查找时需遍历链表(但链表长度通常较短,效率仍较高)。

3. 其他辅助冲突解决方法

(1)再散列法
再散列法(又称双散列法)是当初始地址冲突时,使用第二个散列函数计算探测增量di=H2(key)d_i = H_2(key)di=H2(key)H2(key)H_2(key)H2(key)H(key)H(key)H(key)不同),探测序列为Hi=(H0+i×H2(key))%mH_i = (H_0 + i \times H_2(key)) \% mHi=(H0+i×H2(key))%m。这种方法能进一步减少聚集,但需设计两个散列函数,计算稍复杂。

(2)公共溢出区法
公共溢出区法将散列表分为“基本表”和“溢出表”两部分:所有关键字先尝试存入基本表(按初始散列地址),若发生冲突,则统一存入溢出表;查找时先查基本表,若未找到则查溢出表。这种方法适合冲突较少的场景,溢出表可简化为顺序存储结构。

综上,冲突解决方法的选择需结合实际场景:开放定址法适合散列表容量固定、关键字数量稳定的场景(如嵌入式系统的小型缓存);链地址法适合关键字数量动态变化、追求低聚集的场景(如数据库索引、哈希表容器)。理解不同方法的探测规则和特点,是设计高效散列表的关键。

http://www.dtcms.com/a/523495.html

相关文章:

  • 箭头函数和普通函数有什么区别
  • Spring Boot 缓存知识体系大纲
  • 破局政务数字化核心难题:金仓数据库以国产化方案引领电子证照系统升级之路
  • XML:从基础到 Schema 约束的全方位解析
  • 技术引领场景革新|合合信息PRCV论坛聚焦多模态文本智能前沿实践
  • 海南网站建设网络货运平台有哪些
  • 系统架构设计师备考第53天——业务逻辑层设计
  • 科技创新与数字化制造转型在“十五五”规划中的意义
  • 网站开发最新技术wordpress4.7.4密码
  • HarmonyOS方舟编译器与运行时优化
  • HarmonyOS AI能力集成与端侧推理实战
  • 自己做公众号和小说网站推广济南网站建设艮安
  • 阿里云国际站GPU:阿里云GPU的应用场景有哪些?
  • 【工具】Scrcpy|安卓投屏电脑的开源工具Scrcpy的安装及看电视注意事项
  • penCV轻松入门_面向python(第七章 图像平滑处理)
  • html5移动网站开发流程各类设计型网站
  • 使用C#代码在Excel中创建数据透视表
  • 反爬克星还是效率神器?Browser-Use+cpolar重构Web自动化逻辑
  • 《KingbaseES数据库:首个多院区异构多活容灾架构,浙人医创新开新篇》
  • MySQL 的 MyISAM 与 InnoDB 存储引擎的核心区别
  • 【Qt开发】容器类控件(一)-> QGroupBox
  • 生活电器:重构家居体验的产业变革与发展探索
  • 怎么在百度建立自己的网站58同城西安网站建设
  • Modbus笔记
  • JVM 分代收集算法(Generational GC) 的原理和执行流程
  • 网站名加引号wordpress+极简博客
  • 网站备案取消接入什么是网站反链
  • 淘宝客网站需要多大主机分销网站怎么做
  • 荣县规划和建设局网站wordpress换网址
  • 广州市企业网站建设怎么样合肥做公司网站