深入理解 hash 结构的另一种形式 —— 开放地址法

Hashmap 面试题 + Hashmap 原理 + Hashmap 源码(史上最全) 从根本上来说,一个哈希表包含一个数组,通过特殊的关键码(也就是key)来访问数组中的元素。存放Value的时候,通过一个哈希函数,通过 关键码(key)进行哈希运算得到哈希值,然后得到 映射的位置, 去寻找存放值的地方 ,读取Value的时候,也是通过同一个哈希函数,通过 关键码(key)进行哈希运算得到哈希值,然后得到 映射的位置,从那个位置去读取。... 阅读详情

本文我们来探讨一个数据结构的基础话题:hash 结构

HashMap 无 Java 人不知无 Java 人不晓,它使用开链法处理 hash 碰撞,将碰撞的元素用链表串起来挂在第一维数组上。但是并不是所有语言的字典都使用开链法搞定的,比如 Python,它使用的是另一种形式 —— 开放地址法。相比 HashMap 是二维的结构,它只是一维的,只有一个数组。

开放地址法与开链法的不同之处在于如何处理 hash 冲突。当新来一个元素哈希到数组中的位置已经被其它元素占据了该怎么办?

开放地址法会根据当前的位置计算出下一个位置,将这个冲突的元素挪进来。如果这下一个位置也被占用了,那么就再计算下一个位置,直到找到一个空的位置。可以想像,将会有一条虚拟的链条将这些相关的位置串起来。这个虚拟的链条就好比开链法里面的第二维链表。只不过链表有显示的指针字段,而虚拟链条没有,它的这个链条完全是通过数学函数计算出来的。

root = hash(key) % m   // 第一个位置,m 为数组的长度
index_i = (root + p(key, i)) % m  // 链条中的第 i 个位置

index_1 = (root + p(key, 1)) % m
index_2 = (root + p(key, 2)) % m 
...

在查找的时候,如果第一个位置上保存的 key 不是目标 key,那就沿着探测路径继续寻找,直到找到或者遇到一个空位置为止。

到这里你可能会担心又没有可能探测过程会出现死循环,探来探去又回到原点了,或者是回到路径的中间。这是很有可能的,所以这里的探测函数不能随意选择,它必须保证探测序列不会出现循环,经过 m-1 次探测生成的探测序列必须正好是 1..m-1的全排列。

这样的探测函数有很多,其中最常见的一种是线性探测函数。该探测序列和输入 key 无关。最终的探测路径只和初始位置相关。

// m = 2^n,c 必须是一个奇数
p(key, i) = c * i
index_i = root + c * i

public class HashTest {
    public static void main(String[] args) {
        int m = 1 << 16;
        int c = 111111;
        Set<Integer> nums = new HashSet<>();
        for (int i = 1; i < m; i++) {
            int p = c * i % m;
            if(nums.contains(p)) {
                System.out.println("duplicated");
                return;
            }
            nums.add(p);
        }
        System.out.println("no duplicate");
    }
}

------------
no duplicate

为了不让探测路径中断,删除有两种实现方案

在删除的位置置一个特殊的删除标记,查找时可以直接跳过继续沿着探测路径往后寻找。需要注意的是这个删除的位置在后续的新元素插入时会得到回收利用。插入元素时,遍历探测路径,遇到了第一个删除标记的位置,这时不能立即插入。因为有可能这个元素存在于探测路径的后半部。所以需要遍历到底如果发现确实路径里不存在这个元素,这时候要回过头来插入到第一个发现删除标记的位置。如果删除的位置过多,会影响查找和插入性能。

将探测路径的后半部元素全部删除,然后重新插入。如果路径较长,可能会影响插入性能。

到这里似乎就结束了,其实还有一点我们没有注意到。那就是在采用 p(key, i) = c * i 探测函数的前提下,如果多个不同的 key 哈希的第一个位置相同,那么它们将会共享同一条探测路径。因为探测路径完全由第一个位置来决定的,和 输入 key 无关。那么这些相关的 key 就会在一条探测路径上聚集,这可能会导致数据分布的结果不那么均匀。

如果我们使用一个不同的探测函数,使得它和输入 key 相关,那么就可以消灭这个聚集问题。我们可以将探测函数中的常量 c 换成一个 hash 函数,只要这个函数总是返回奇数就可以了,这样的 hash 函数还是非常容易编写的。

p(key, i) = h2(key) * i

640?wx_fmt=png

哈希查找算法之线性探测法(开放地址法) 哈希查找是一种时间复杂度为O(1)的一种效率极高的查找方法,与常见的遍历查找不同,哈希算法是通过数组元素数值与哈希表下标构建的一种查找方法,因此我们不需要遍历整个数组,即可对其进行访问。... 阅读详情

相关推荐

深入理解HashMap:Hash冲突的解决机制

`HashMap` 是 Java 集合框架中最常用的数据结构之一,它通过键值对的形式存储数据,并利用哈希算法实现高效的插入、删除和查询操作。然而,在实际使用中,由于哈希函数的有限性和哈希桶数量的限制,不可避免地会出现 **哈希冲突**(即不同的键映射到同一个哈希桶)。本文将深入探讨 `HashMap` 如何解决哈希冲突,并结合源码和 Mermaid 图表帮助你更好地理解其工作机制。

weixin_43063493的博客 1452

开放地址法开放地址法

开放地址法是指大小为 M 的数组保存 N 个键值对,其中 M > N。我们需要依靠数组中的空位解决碰撞冲突。基于这种策略的所有方法被统称为“开放地址”哈希表。线性探测法,就是比较常用的一种“开放地址”哈希表的一种实现方式。线性探测法的核心思想是当冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。简单来说就是:一旦发生冲突,就去寻找下 一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。 线性探测法的数学描述是:h(k, i) = (h(k, 0) + i) mod m,i表示当

地推 4791

哈希算法:从数字指纹到密码存储,全面解析核心原理与实战应用

哈希算法是一种将任意长度数据映射为固定长度摘要的核心技术,其确定性、高效性和单向性构成了数字世界的信任基石。从原理上看,哈希函数通过复杂的数学运算生成唯一的“数字指纹”,具备雪崩效应和抗碰撞性,确保数据的微小变动都会导致哈希值巨变,且难以找到两个不同输入产生相同输出。这一技术价值在于,它不仅是数据完整性校验和篡改检测的关键,更是现代密码学和安全体系的基础组件。在应用场景上,哈希算法广泛应用于软件包校验、版本控制系统、密码安全存储以及区块链技术中。例如,在密码存储领域,通过加盐和工作因子等机制,可以有效抵御彩

ctk87443的博客 382

HashMap底层——解决Hash冲突(开放地址法)

开放地址法 1、Hash函数 Hash函数就是将任意长度的输入转化成固定长度的输出的一类函数 举例说明 比如说我的输入是任意一个自然数(0,1,2,3…),而我要求经过一个函数后我的输出的数的范围要在0-9这样一个范围之间。 很容易想到,我们可以使用Hash函数: key就是输入; 在哈希表(散列表)里,Hash函数的作用就是将关键字Key转化为一个固定长度数组的下标,以便存取键值对<Key,Value> Hash冲突解决的两个办法 链地址法. 开放地址法 所谓开放地址法就是发

sulayman的博客 2772

深入浅出:小程序中哈希算法的实现与应用

哈希函数,作为信息安全的核心技术之一,在IT领域扮演着至关重要的角色。简单来说,哈希函数将任意长度的输入(通常是一个字符串)通过算法处理,转换为固定长度的输出,通常是一个较短的字符串,也称为哈希值或摘要。其在数据完整性验证、密码存储、数字签名、区块链技术等多个方面有着广泛的应用。本章将对哈希函数在IT领域的应用进行概述,引领读者进入哈希函数的世界。

weixin_42466857的博客 660

定制PYNQ的overlay

一、用HLS生成一个定制IP(加速器)(1)首先打开vivado hls,本人的版本是2017.2,点击创建一个新工程。(2)设置工程名和路径,顶层函数设置为add,创建一个新的C++程序,名字叫做adder.cpp,不用在testbench中添加文件。选择板子的时候搜索xc7z020clg400-1,这是PYNQ的板子号,选择完成。             (3)在左侧的菜单栏里选择Sourc...

bramblewalls的博客 1万+

面试经典-基于开放地址手写hashmap

由于哈希值的空间远小于输入的空间,所以经过散列处理后,仍然会出现不同的数据对应相同的数组下标,这时候就产生了哈希冲突。

Winn~ 345

DDR5内存调优实战:手把手教你搞定Write Leveling Training Mode(附时序图解析)

本文深入解析DDR5内存调优中的Write Leveling Training Mode技术,详细介绍了其核心原理、硬件准备、实战步骤及常见问题解决方案。通过JESD79-5标准定义的反馈机制,帮助硬件工程师精确对齐DQS与CK信号,提升系统稳定性和数据可靠性。附有时序图解析和代码示例,适合DDR5内存系统设计与调试参考。

weixin_29256771的博客 549

hash地址_深入理解 hash 结构的另一种形式 —— 开放地址法

本文我们来探讨一个数据结构的基础话题:hash 结构HashMap 无 Java 人不知无 Java 人不晓,它使用开链法处理 hash 碰撞,将碰撞的元素用链表串起来挂在第一维数组上。但是并不是所有语言的字典都使用开链法搞定的,比如 Python,它使用的是另一种形式 —— 开放地址法。相比 HashMap 是二维的结构,它只是一维的,只有一个数组。开放地址法与开链法的不同之处在于如何...

weixin_39857153的博客 549

WKWebView 白屏问题,WKWebView request body丢失问题

1,WKWebView 白屏问题 WKWebView 自诩拥有更快的加载速度,更低的内存占用,但实际上 WKWebView 是一个多进程组件,Network Loading 以及 UI Rendering 在其它进程中执行。初次适配 WKWebView 的时候,我们也惊讶于打开 WKWebView 后,App 进程内存消耗反而大幅下降,但是仔细观察会发现,Other Process 的内存占用会...

weixin_37543822的博客 734

MATLAB2021b详细安装教程

1.下载 2.安装 下载安装包后打开iso文件,若是无法打开请用解压软件打开。 ①打开MATLAB_R2021b_win64,双击软件开始安装 ② 一直点击下一步,直到步骤③ ③选择我已有我的许可证的文件密钥,并输入62551-02011-26857-57509-64399-54230-13279-37181-62117-65158-40352-64197-45508-24369-45954-39446-39538-16936-10698-58393-44718-32560-10501-40

惜洛-Jankin的博客 9万+

数据结构与算法——深入理解哈希表

文章目录哈希表优点与缺点哈希化冲突基于线性探测的开放地址法插入查找删除性能问题基于二次探测的开放地址法基于再哈希法的开放地址法链地址法哈希表实现方法的选择参考 哈希表 哈希表是一种数据结构,基于数组实现,但存取方式和数组不同。 哈希表可以认为是一种特殊的数组,一个重要的特性是“数据项的关键字与数组下标有关联”。(数据项的关键字经过简单计算便可得到数组下标,从而实现快速存取) 优点与缺点 优点 提供快速的插入操作和查找操作,时间复杂度接近O(1)。 编程实现相对容易。 缺点 基于数组,一是创建后难

ChenTianyu的博客 2547

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的生活垃圾检测与分类系统(Python+PySide6界面+训练代码)

随着城市化进程的加速和人口增长,生活垃圾管理已成为现代城市面临的重要挑战。传统的垃圾处理方法效率低下且成本高昂,急需智能化解决方案。本文详细介绍了基于YOLO系列算法(特别是YOLOv8)的智能生活垃圾检测与分类系统,该系统能够实时识别和分类多种生活垃圾,为智能垃圾处理和回收提供技术支持。系统包含完整的数据集构建、模型训练、评估和可视化界面,并提供了完整的实现代码。

YOLO 117

ds哈希查找--链地址法_Hash冲突之开放地址法

来源:趣谈编程作者:趣谈编程Hash碰撞慧能一尘,国庆节过完了,还记得Hash函数吗?当然记得了,Hash函数就是将任意长度的输入转化成固定长度的输出的一类函数一尘比如说我的输入是任意一个自然数(0,1,2,3...),而我要求经过一个函数后我的输出的数的范围要在0-9这样一个范围之间。很容易想到,我们可以使用Hash函数:其中key就是输入在哈希表(散列表)里,Hash函数的作用就是将...

weixin_34073886的博客 353

OpenClaw第2章:快速安装

本章将手把手教你安装 OpenClaw。

Maynor的博客 3235

机器视觉框架源码——解读5(Dock和开源UI)

本文介绍了工业软件中Dock工具面板的使用方法,主要包括三个部分:添加avalonDock引用、修改属性配置(如显示样式和背景色),以及通过MVVM命令实现布局的加载和保存。加载布局通过XmlLayoutSerializer从XML文件恢复界面状态,保存布局则将当前DockManager的布局序列化为XML文件。文章提供了代码示例和截图说明,帮助开发者快速掌握Dock面板的核心功能。

Z's Palace 401

string生成固定长度的哈希_一文读懂区块链中的哈希算法

今天给大家介绍一下哈希算法。其实就是计算区块的哈希值,通过生成区块头部的随机数来调整每次哈希的结果,使得计算出来的区块的哈希值符合一个特定标准。那么哈希是什么呢?又为什么需要用哈希算法来挖矿?一、概念初识哈希算法,又称散列算法,就是指一种把任何长度的数据提炼出固定长度数字“指纹”的方法。哈希算法有一个输入和一个输出,输入时任意长度的数据,在算法内部不管输入的数据是何种形式,都以单纯的比特序列来处理...

weixin_39580748的博客 732

手把手教你学simulink(26.8)--控制算法场景示例:基于强化学习的无人机姿态稳定控制系统

首先,我们需要定义无人机的姿态稳定控制环境。环境包括无人机的状态(姿态角、角速度等)和动作(电机转速)。我们还需要定义奖励函数,用于评估控制器的表现。matlab深色版本% 定义环境% 定义状态空间% 12个状态变量% 定义动作空间% 电机转速范围奖励函数用于评估控制器的表现。我们可以根据无人机的姿态误差、角速度误差以及控制输入的变化率来设计奖励函数。具体来说,当无人机的姿态接近设定值时,给予正奖励;当姿态误差较大或控制输入变化剧烈时,给予负奖励。matlab深色版本。

MHD0815的博客 494

数据结构与算法(6)哈希表

数据结构与算法(6)哈希表

weixin_63714970的博客 1987

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深入理解 Rust HashMap:哈希算法与冲突解决机制解析

Rust标准库中的HashMap通过SipHash-1-3算法和Robin Hood哈希策略实现安全与性能的平衡。默认使用随机种子防御哈希泛洪攻击,确保O(1)时间复杂度。对于高性能场景,可选用AHash等快速哈希器。采用开放寻址和负载因子自动扩容机制,通过87.5%阈值触发再哈希。实际应用中应权衡安全需求与性能,合理选择哈希器,善用entry API并关注负载策略,以优化程序性能。

2301_80396173的博客 635

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【数据结构与算法】哈希冲突和解决方法

既然要访问,那肯定需要知道访问的内容存放在哪里,所以这就需要通过一种映射关系将访问元素的关键字和元素的存储地址关联起来,而这种映射关系就是通过哈希函数来实现的。因为通过哈希函数产生的值是有限的,而数据可能比较多,导致通过哈希函数映射后仍有很多不同的数据对应了相同的哈希值,这时候就产生了哈希冲突。**基本思想是:**对于冲突的哈希值,再构造另一个哈希函数进行处理,直至没有哈希冲突,也就是同时使用多个哈希函数来处理。,可以发现,有些原本不同的数据却对应到了相同的哈希值上了,因此发生了冲突。

热情、奔放、快乐编程! 1343

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

哈希表基本知识简介

文章目录一、哈希表简介二、哈希函数2.1直接定址法2.2 除留余数法2.3平方取中法2.4 基数转换法三、哈希冲突3.1 开放地址法2.读入数据总结 一、哈希表简介 哈希表:也叫做散列表,是根据关键字和值(Key Value)直接进行访问的数据结构,即通过一个关键字Key和一个映射函数Hash计算出对应的值Value,然后把键值对映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做哈希函数,用于存放记录的数组叫做哈希表。 关键在于如何使用哈希函数: 向哈希表中插入一个关键字:哈希函数决定该关

zsc19990913的博客 2265

哈希算法终极指南:从基础应用到高级优化的完整解析

哈希算法是计算机科学中一种高效的数据处理技术,它通过将任意长度的输入转换为固定长度的输出,实现快速数据查找和比对。本文将带你从哈希表的基础应用开始,逐步深入哈希算法的核心原理与高级优化技巧,帮助你彻底掌握这一必备技能。 ## 一、哈希表:哈希算法的入门实践 哈希表(Hash Table)是哈希算法最基础也最广泛的应用,它通过建立键值对的映射关系,实现了O(1)时间复杂度的查找效率。在LeetC

gitblog_00453的博客 932

【C++笔记】 Hash(哈希) C++ STL中哈希表 hash_map从头到尾详细介绍(转)

参考: 1. 深入理解HashMap Java 2. C++ STL中哈希表 hash_map从头到尾详细介绍     Hashmap是一种非常常用的、应用广泛的数据类型,最近研究到相关的内容,就正好复习一下。网上关于hashmap的文章很多,但到底是自己学习的总结,就发出来跟大家一起分享,一起讨论。 1、hashmap的数据结构  要知道hashmap是什么,首先要搞清楚它的数据结构,在...

Twinkle 3207

哈希表与哈希冲突(Hash表 散列表)

哈希表(Hash table 又叫散列表)是能够通过给定的关键字的值直接访问到具体对应的值的一个数据结构。通常,我们把这个关键字称为Key值,对应的值称为Value值。关键值和Value值是一种一一对应的关系(也就是映射关系),这个映射表,也叫做哈希函数,存放记录的数组就是哈希表。哈希表也类似于离散化。 哈希表的作用:哈希表的作用就是能够通过Key值快速获取Key对应的Value值,它查询的时间复杂度几乎是O(1)的,

qq_46056407的博客 775
上一篇: Redis 精确去重计数 —— 咆哮位图
下一篇: 布隆过滤器过时了,未来属于布谷鸟过滤器?
codehole_
博客等级 码龄7年 34粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值