深入理解开放寻址法中的三种探测序列
一、引言
开放寻址法是解决散列表中冲突的一种重要方法,当发生冲突(即两个不同的键通过散列函数计算得到相同的散列值)时,它会在散列表中寻找下一个可用的存储位置。而探测序列就是用于确定在发生冲突后,依次尝试哪些存储位置的规则。下面详细介绍线性探测、二次探测和双重散列这三种常见的探测序列。

二、线性探测(Linear Probing)
1. 原理
线性探测是最简单的开放寻址法探测序列。当插入一个键值对,计算出的散列值对应的存储位置已被占用时,它会按照顺序依次检查下一个存储位置(通常是逐个向后检查),直到找到一个空的存储位置为止。如果检查到散列表的末尾还没有找到空位置,就会从散列表的开头继续检查。其探测函数的公式为:
h ( k , i ) = ( h ′ ( k ) + i ) m o d m h(k, i) = (h'(k)+i) \bmod m h(k,i)=(h′(k)+i)modm
其中, h ( k , i ) h(k, i) h(k,i) 是经过 i i i 次探测后得到的存储位置, h ′ ( k ) h'(k) h′(k) 是初始的散列值(即通过散列函数直接计算得到的位置), i i i 是探测次数( i = 0 , 1 , 2 , ⋯ i = 0, 1, 2, \cdots i=0,1,2,⋯), m m m 是散列表的大小。
2. 示例
假设散列表的大小 m = 10 m = 10 m=10,散列函数 h ′ ( k ) = k m o d 10 h'(k)=k \bmod 10 h′(k)=kmod10。现在要依次插入键 23 23 23、 33 33 33、 43 43 43。
- 插入键 23 23 23: h ′ ( 23 ) = 23 m o d 10 = 3 h'(23)=23 \bmod 10 = 3 h′(23)=23mod10=3,位置 3 3 3 为空,直接插入。
- 插入键 33 33 33: h ′ ( 33 ) = 33 m o d 10 = 3 h'(33)=33 \bmod 10 = 3 h′(33)=33mod10=3,位置 3 3 3 已被占用,进行第一次探测 i = 1 i = 1 i=1, h ( 33 , 1 ) = ( 3 + 1 ) m o d 10 = 4 h(33, 1)=(3 + 1)\bmod 10 = 4 h(33,1)=(3+1)mod10=4,位置 4 4 4 为空,插入到位置 4 4 4。
- 插入键 43 43 43: h ′ ( 43 ) = 43 m o d 10 = 3 h'(43)=43 \bmod 10 = 3 h′(43)=43mod10=3,位置 3 3 3 已被占用,进行第一次探测 i = 1 i = 1 i=1, h ( 43 , 1 ) = ( 3 + 1 ) m o d 10 = 4 h(43, 1)=(3 + 1)\bmod 10 = 4 h(43,1)=(3+1)mod10=4,位置 4 4 4 也被占用,进行第二次探测 i = 2 i = 2 i=2, h ( 43 , 2 ) = ( 3 + 2 ) m o d 10 = 5 h(43, 2)=(3 + 2)\bmod 10 = 5 h(43,2)=(3+2)mod10=5,位置 5 5 5 为空,插入到位置 5 5 5。
3. 优缺点
- 优点:实现简单,只需要进行简单的加法和取模运算。
- 缺点:容易产生“聚集”现象,即连续被占用的存储位置会越来越长,导致后续插入和查找操作的效率降低。
三、二次探测(Quadratic Probing)
1. 原理
二次探测通过二次函数来确定探测序列,它在发生冲突时,不是像线性探测那样逐个向后检查,而是按照二次方的步长来检查存储位置。其探测函数的公式为:
h ( k , i ) = ( h ′ ( k ) + c 1 i + c 2 i 2 ) m o d m h(k, i)=(h'(k)+c_1i + c_2i^2) \bmod m h(k,i)=(h′(k)+c1i+c2i2)modm
其中, c 1 c_1 c1 和 c 2 c_2 c2 是正的常数, h ′ ( k ) h'(k) h′(k) 是初始散列值, i i i 是探测次数( i = 0 , 1 , 2 , ⋯ i = 0, 1, 2, \cdots i=0,1,2,⋯), m m m 是散列表的大小。常见的情况是 c 1 = c 2 = 1 c_1 = c_2 = 1 c1=c2=1。
2. 示例
同样假设散列表的大小 m = 10 m = 10 m=10,散列函数 h ′ ( k ) = k m o d 10 h'(k)=k \bmod 10 h′(k)=kmod10, c 1 = c 2 = 1 c_1 = c_2 = 1 c1=c2=1。要插入键 23 23 23、 33 33 33、 43 43 43。
- 插入键 23 23 23: h ′ ( 23 ) = 23 m o d 10 = 3 h'(23)=23 \bmod 10 = 3 h′(23)=23mod10=3,位置 3 3 3 为空,直接插入。
- 插入键 33 33 33: h ′ ( 33 ) = 33 m o d 10 = 3 h'(33)=33 \bmod 10 = 3 h′(33)=33mod10=3,位置 3 3 3 已被占用,进行第一次探测 i = 1 i = 1 i=1, h ( 33 , 1 ) = ( 3 + 1 × 1 + 1 × 1 2 ) m o d 10 = 5 h(33, 1)=(3+1\times1 + 1\times1^2)\bmod 10 = 5 h(33,1)=(3+1×1+1×12)mod10=5,位置 5 5 5 为空,插入到位置 5 5 5。
- 插入键 43 43 43: h ′ ( 43 ) = 43 m o d 10 = 3 h'(43)=43 \bmod 10 = 3 h′(43)=43mod10=3,位置 3 3 3 已被占用,进行第一次探测 i = 1 i = 1 i=1, h ( 43 , 1 ) = ( 3 + 1 × 1 + 1 × 1 2 ) m o d 10 = 5 h(43, 1)=(3+1\times1 + 1\times1^2)\bmod 10 = 5 h(43,1)=(3+1×1+1×12)mod10=5,位置 5 5 5 也被占用,进行第二次探测 i = 2 i = 2 i=2, h ( 43 , 2 ) = ( 3 + 1 × 2 + 1 × 2 2 ) m o d 10 = 9 h(43, 2)=(3+1\times2 + 1\times2^2)\bmod 10 = 9 h(43,2)=(3+1×2+1×22)mod10=9,位置 9 9 9 为空,插入到位置 9 9 9。
3. 优缺点
- 优点:一定程度上缓解了线性探测的“聚集”问题,因为它的探测步长是变化的。
- 缺点:仍然可能出现二次聚集的情况,即不同的初始散列值可能会产生相同的探测序列。
四、双重散列(Double Hashing)
1. 原理
双重散列使用两个散列函数来确定探测序列。当发生冲突时,它会根据第二个散列函数计算出的步长来依次检查存储位置。其探测函数的公式为:
h ( k , i ) = ( h 1 ( k ) + i × h 2 ( k ) ) m o d m h(k, i)=(h_1(k)+i\times h_2(k)) \bmod m h(k,i)=(h1(k)+i×h2(k))modm
其中, h 1 ( k ) h_1(k) h1(k) 是第一个散列函数计算得到的初始散列值, h 2 ( k ) h_2(k) h2(k) 是第二个散列函数, i i i 是探测次数( i = 0 , 1 , 2 , ⋯ i = 0, 1, 2, \cdots i=0,1,2,⋯), m m m 是散列表的大小。为了保证能够遍历散列表中的所有位置, h 2 ( k ) h_2(k) h2(k) 的值必须与 m m m 互质。
2. 示例
假设散列表的大小 m = 10 m = 10 m=10,第一个散列函数 h 1 ( k ) = k m o d 10 h_1(k)=k \bmod 10 h1(k)=kmod10,第二个散列函数 h 2 ( k ) = 7 − ( k m o d 7 ) h_2(k)=7-(k \bmod 7) h2(k)=7−(kmod7)。要插入键 23 23 23、 33 33 33、 43 43 43。
- 插入键 23 23 23: h 1 ( 23 ) = 23 m o d 10 = 3 h_1(23)=23 \bmod 10 = 3 h1(23)=23mod10=3,位置 3 3 3 为空,直接插入。
- 插入键 33 33 33: h 1 ( 33 ) = 33 m o d 10 = 3 h_1(33)=33 \bmod 10 = 3 h1(33)=33mod10=3,位置 3 3 3 已被占用, h 2 ( 33 ) = 7 − ( 33 m o d 7 ) = 7 − 5 = 2 h_2(33)=7-(33 \bmod 7)=7 - 5 = 2 h2(33)=7−(33mod7)=7−5=2,进行第一次探测 i = 1 i = 1 i=1, h ( 33 , 1 ) = ( 3 + 1 × 2 ) m o d 10 = 5 h(33, 1)=(3+1\times2)\bmod 10 = 5 h(33,1)=(3+1×2)mod10=5,位置 5 5 5 为空,插入到位置 5 5 5。
- 插入键 43 43 43: h 1 ( 43 ) = 43 m o d 10 = 3 h_1(43)=43 \bmod 10 = 3 h1(43)=43mod10=3,位置 3 3 3 已被占用, h 2 ( 43 ) = 7 − ( 43 m o d 7 ) = 7 − 1 = 6 h_2(43)=7-(43 \bmod 7)=7 - 1 = 6 h2(43)=7−(43mod7)=7−1=6,进行第一次探测 i = 1 i = 1 i=1, h ( 43 , 1 ) = ( 3 + 1 × 6 ) m o d 10 = 9 h(43, 1)=(3+1\times6)\bmod 10 = 9 h(43,1)=(3+1×6)mod10=9,位置 9 9 9 为空,插入到位置 9 9 9。
3.优缺点
- 优点:是开放寻址法中最好的方法之一,能更均匀地分布键,减少聚集现象,使插入、查找和删除操作的平均性能更接近理想情况。
- 缺点:需要设计两个散列函数,实现相对复杂,计算开销也会稍微大一些。
相关文章:
深入理解开放寻址法中的三种探测序列
一、引言 开放寻址法是解决散列表中冲突的一种重要方法,当发生冲突(即两个不同的键通过散列函数计算得到相同的散列值)时,它会在散列表中寻找下一个可用的存储位置。而探测序列就是用于确定在发生冲突后,依次尝试哪些…...
图像噪声处理技术:让图像更清晰的艺术
在这个数字化时代,图像作为信息传递的重要载体,其质量直接影响着我们的视觉体验和信息解读。然而,在图像采集、传输或处理过程中,难免会遇到各种噪声干扰,如高斯噪声、椒盐噪声等,这些噪声会降低图像的清晰…...
linux运行级别
运行级别:指linux系统在启动和运行过程中所处的不同的状态。 运行级别之间的切换:init (级别数) 示例: linux的运行级别一共有7种,分别是: 运行级别0:停机状态 运行级别1:单用户模式/救援模式…...
深入剖析Electron的原理
Electron是一个强大的跨平台桌面应用开发框架,它允许开发者使用HTML、CSS和JavaScript来构建各种桌面应用程序。了解Electron的原理对于开发者至关重要,这样在设计应用时能更合理,遇到问题也能更准确地分析和解决。下面将从多个方面深入剖析E…...
C++ 游戏开发:完整指南
目录 什么是游戏开发? 为什么选择 C 进行游戏开发? C 游戏开发:完整指南 1. 理解游戏开发的基础 2. 学习游戏引擎 3. 精通 C 进行游戏开发 4. 学习数学在游戏开发中的应用 5. 探索图形编程 6. 专注于游戏开发的某一领域 7. 通过游戏项目进行实…...
WebForms SortedList 深度解析
WebForms SortedList 深度解析 引言 在Web开发领域,对于数据结构的理解与应用至关重要。其中,SortedList类在WebForms中是一个常用的数据结构,它能够帮助开发者高效地管理有序数据集合。本文将深入解析SortedList类在WebForms中的应用,包括其基本概念、常用方法、性能特点…...
【hot100】刷题记录(12)-回文链表
题目描述: 给你一个单链表的头节点 head ,请你判断该链表是否为 回文链表 。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:head [1,2,2,1] 输出:true示例 2: …...
深入理解 Unix Shell 管道 Pipes:基础和高级用法 xargs tee awk sed等(中英双语)
深入理解 Unix Shell 管道(|) 1. 什么是管道(Pipe)? 管道(|)是 Unix/Linux Shell 中最强大的功能之一,它允许将一个命令的输出作为另一个命令的输入,从而实现数据流的处…...
[MySQL]事务的理论、属性与常见操作
目录 一、事物的理论 1.什么是事务 2.事务的属性(ACID) 3.再谈事务的本质 4.为什么要有事务 二、事务的操作 1.事务的支持版本 2.事务的提交模式 介绍 自动提交模式 手动提交模式 3.事务的操作 4.事务的操作演示 验证事务的回滚 事务异常…...
RS485接口EMC
A.滤波设计要点 L1为共模电感,共模电感能够衰减共模干扰,对单板内部的干扰以及外部的干扰都能抑制,能提高产品的抗干扰能力,同时也能减小通过485信号线对外的辐射,共模电感阻抗选择范围为120Ω/100MHz ~2200Ω/100MHz…...
快速上手mybatis教程
基础知识 MyBatis 是一款优秀的持久层框架,其核心组件主要包括以下部分: SqlSession 作用:SqlSession 是 MyBatis 的核心接口,负责与数据库进行通信,执行 SQL 语句,并返回查询结果。它是 MyBatis 的一次会…...
本地部署DeepSeek-R1保姆级教程
近期,我国一款开源模型 DeepSeek-R1以低成本和高性能震撼了全球科技界。该模型的开源性使开发者能够在本地环境中部署和运行,提供了更高的灵活性和控制力。如果你也想在本地部署 DeepSeek-R1,可以参考以下完整的教程,涵盖Mac 版本…...
blender 相机参数
目录 设置相机参数: 3. 设置相机参数示例 4. 相机透视与正交 5. 额外的高级设置 设置相机参数: 设置渲染器: 外参转换函数 转换测试代码: 获取blender渲染外参: 设置相机参数: 3. 设置相机参数示…...
在GPIO控制器中,配置通用输入,读取IO口电平时,上拉和下拉起到什么作用
上下拉电阻作用 在通用输入的时候,也就是在读某个IO的电平的时候 一定要让IO口先保持一个电平状态,这样才能检测到不同电平状态。 如何保持电平状态? 1. 可以通过芯片内部的上下拉电阻,由于是弱上下拉一般不用 2. 硬件外界一个…...
Maven工程核心概念GAVP详解:从命名规范到项目协作的基石
Maven工程核心概念GAVP详解:从命名规范到项目协作的基石 一、GAVP是什么? 在Maven工程中,GAVP是四个核心属性的缩写:GroupId、ArtifactId、Version、Packaging。这组属性为项目在Maven仓库中提供了唯一标识,类似于“项…...
如何利用DeepSeek打造医疗领域专属AI助手?从微调到部署全流程解析
如何利用DeepSeek开源模型打造医疗领域专属AI助手?从微调到部署全流程解析 医疗人工智能正迎来爆发式增长,但在实际应用中,通用大模型往往存在医学知识不精准、诊断逻辑不严谨等问题。本文将手把手带您实现医疗垂直领域大模型的定制化训练&a…...
Redis|前言
文章目录 什么是 Redis?Redis 主流功能与应用 什么是 Redis? Redis,Remote Dictionary Server(远程字典服务器)。Redis 是完全开源的,使用 ANSIC 语言编写,遵守 BSD 协议,是一个高性…...
眼见着折叠手机面临崩溃,三星计划增强抗摔能力挽救它
据悉折叠手机开创者三星披露了一份专利,通过在折叠手机屏幕上增加一个抗冲击和遮光层的方式来增强折叠手机的抗摔能力,希望通过这种方式进一步增强折叠手机的可靠性和耐用性,来促进折叠手机的发展。 据悉三星和研发可折叠玻璃的企业的做法是在…...
Leetcode面试高频题分类刷题总结
https://zhuanlan.zhihu.com/p/349940945 以下8个门类是面试中最常考的算法与数据结构知识点。 排序类(Sort): 基础知识:快速排序(Quick Sort), 归并排序(Merge Sort)的…...
Vue.js `v-memo` 性能优化技巧
Vue.js v-memo 性能优化技巧 今天我们来聊聊 Vue 3.2 引入的一个性能优化指令:v-memo。如果你在处理大型列表或复杂组件时,遇到性能瓶颈,那么 v-memo 可能会成为你的得力助手。 什么是 v-memo? v-memo 是 Vue 3.2 新增的内置指…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
