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

这个就是哈希冲突

哈希冲突(Hash Collision),也称为哈希碰撞,是指两个或多个不同的输入数据(键)经过哈希函数计算后,得到了相同的哈希值,从而被映射到哈希表(或散列表)的同一个存储位置上

简单来说,就是不同的“钥匙”(键)打开了同一把“锁”(哈希地址)。

为什么会产生哈希冲突?

哈希冲突是不可避免的,主要原因如下:

  1. 输入空间无限,输出空间有限:哈希函数的输入(即可能的键)可以是无限多的(例如,任意长度的字符串、数字),而哈希表的大小是固定的,其地址空间是有限的。根据鸽巢原理(Pigeonhole Principle),当把无限多的“鸽子”放进有限的“鸽巢”里时,至少有一个“巢”里会有多于一只“鸽子”,即必然会发生冲突。
  2. 哈希函数的压缩性:哈希函数的本质是将一个大范围的数据压缩到一个小范围的索引。这种压缩过程本身就可能导致不同的输入被压缩到同一个输出。
  3. 哈希函数设计或数据分布:如果哈希函数设计得不够好(例如,不够均匀、随机),或者输入数据的分布本身就有规律(例如,大量键的尾数相同),也可能增加冲突发生的概率。

举个例子

假设我们有一个简单的哈希函数:hash(key) = key % 10,并且哈希表的大小为10。

  • 当 key = 5 时,hash(5) = 5 % 10 = 5,数据存放在索引5的位置。
  • 当 key = 15 时,hash(15) = 15 % 10 = 5,它也想存放在索引5的位置。
  • 当 key = 25 时,hash(25) = 25 % 10 = 5,它同样想存放在索引5的位置。

此时,键 51525 虽然不同,但都映射到了索引5,这就发生了哈希冲突。

如何解决哈希冲突?

为了解决冲突,确保所有数据都能被正确存储和查找,主要有以下几种方法:

  1. 链地址法 (Chaining / Separate Chaining)

    • 原理:将哈希表的每个槽位(bucket)都设计成一个链表(或其他数据结构,如红黑树)的头指针。当发生冲突时,新的元素不是替换旧元素,而是以链表节点的形式链接到该槽位已有的元素后面。
    • 优点:实现简单,增删改查逻辑清晰,对哈希函数要求相对较低。
    • 缺点:当链表过长时,查找效率会下降(接近O(n))。为了解决这个问题,Java 8 的 HashMap 在链表长度超过一定阈值(默认为8)时,会将链表转换为红黑树,将查找时间复杂度优化到O(log n)。
    • 应用:Java 的 HashMapLinkedHashMapConcurrentHashMap(在一定条件下)都使用了链地址法。
  2. 开放地址法 (Open Addressing)

    • 原理:当发生冲突时,不使用额外的链表结构,而是在哈希表内部寻找下一个“空”的槽位来存放发生冲突的元素。查找时,如果目标位置不是要找的元素,也需要沿着相同的探测序列继续查找。
    • 常见的探测方法
      • 线性探测 (Linear Probing):如果 hash(key) 位置被占用,则尝试 (hash(key) + 1) % table_size,如果还被占用,再尝试 +2,依此类推。
      • 二次探测 (Quadratic Probing):探测序列为 hash(key)(hash(key) + 1²) % table_size(hash(key) + 2²) % table_size, ...,旨在减少“聚集”现象。
      • 双重哈希 (Double Hashing):使用第二个哈希函数 hash2(key) 来计算探测步长,序列为 hash(key)(hash(key) + hash2(key)) % table_size(hash(key) + 2*hash2(key)) % table_size, ...,能更均匀地分布元素。
    • 优点:避免了指针的开销,数据存储更紧凑,缓存局部性好。
    • 缺点:容易产生“聚集”(Clustering),即连续的被占用槽位,导致查找效率下降。删除操作比较复杂(通常需要标记为“已删除”而非真正删除)。当哈希表快满时,性能急剧下降,需要及时扩容。
  3. 再哈希法 (Rehashing)

    • 原理:当发生冲突时,使用另一个不同的哈希函数重新计算哈希地址,直到找到一个空的槽位为止。
    • 优点:理论上可以减少冲突。
    • 缺点:需要设计多个高质量的哈希函数,计算开销可能增大。
  4. 建立公共溢出区 (Overflow Area)

    • 原理:将哈希表分为基本表和溢出表两部分。凡是发生冲突的元素,都统一放到溢出表中。
    • 查找:先在基本表中查找,如果没找到再去溢出表中查找。
    • 缺点:查找效率依赖于溢出表的大小和查找方式,实现相对复杂,不常用。

归纳:哈希冲突是哈希表机制中不可避免的现象。链地址法开放地址法是最主流的两种解决方案。像Java HashMap这样的广泛应用,就采用了链地址法结合红黑树优化的策略来高效地处理哈希冲突。

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

相关文章:

  • AI出题人给出的Java后端面经(十四)(日更)
  • 智慧养老解决方案:破解“最后一公里”服务难题
  • 【98页PPT】智慧方案某著名企业汽配行业ERP整体解决方案(附下载方式)
  • BGP笔记及实验
  • 网络层协议——IP
  • 2025年机器视觉与信号处理国际会议(MVSP 2025)
  • 72小时到24小时:台风“杨柳”过后,有鹿机器人如何为园区按下“加速键”?
  • SpringBoot 实现在线查看内存对象拓扑图 —— 给 JVM 装上“透视眼”
  • 面试题之项目中灰度发布是怎么做的
  • 16 ABP Framework CLI
  • Steam修改游戏安装目录
  • 通过beeware制作安卓apk用于获取cpolar网址
  • 【从零开始学习Redis】项目实战-黑马点评D1
  • Docker network网络管理入门教程
  • OpenCV 在图像上绘制二维图形的类cv::plot::Plot2d
  • 心灵笔记:沟通与协作
  • 搭建纯积分商城的关键注意事项
  • MySQL中的DML(二)
  • Spring基础面试题(三)
  • rtthread - ROMFS 的使用方式
  • 【自动驾驶】自动驾驶概述 ① ( 自动驾驶 与 无人驾驶 | 自动驾驶 相关岗位 及 技能需求 )
  • 网络安全应急响应
  • Java Stream API:让业务数据处理更优雅
  • 【120页PPT】人工智能与数字化转型的业财融合(附下载方式)
  • TDengine IDMP 基本功能(6. 无问智推)
  • Web攻防-业务逻辑篇APP隐私合规资源处理违规收集拒绝服务在线检测项目工具
  • 深度剖析!体育数据 API 及电竞数据 API 在体育电竞领域的核心地位
  • java动态代理机制I(初稿)
  • 职得AI简历-免费AI简历生成工具
  • C++ 排序指南