hash表如何形成,hash函数如何计算,什么是hash冲突 如何解决 ,Golang map的底层原理及扩容机制

news2024/12/23 21:01:01

散列表

散列表(hash表):根据给定的关键字来计算出关键字在表中的地址的数据结构。也就是说,散列表建立了关键字和
存储地址之间的一种直接映射关系。

问题:如何建立映射管血

散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr.

hash冲突

散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为“冲突
这些发生碰撞的不同关键字称为同义词。

image-20240730141829195

构造散列函数的条件:

  • 散列函数的定义域必须包含全部需要存储的关键字,而值域的范围则依赖于散列表的大小或地址范围。
  • 散列函数计算出来的地址应该能等概率、均匀地分布在整个地址空间,从而减少冲突的发生。
  • 散列函数应尽量简单,能够在较短的时间内就计算出任一关键字对应的散列地址。
1.常用的Hash函数的构造方法:
  • 直接定址法:直接取关键字的某个线性函数值为散列地址,散列函数为H(key)=axkey+b。式中,a和b是
    常数。这种方法计算最简单,并且不会产生冲突
  • 除留余数法:假定散列表表长为m,取一个不大于m但最接近或等于m的质数p,利用以下公式把关键字
    转换成散列地址。散列函数为H(kev)=key %p
    除留余数法的关键是选好p,使得每一个关键字通过该函数转换后等概率地映射到散列空间上的任一地址
    从而尽可能减少冲突的可能性
  • 数字分析法
    设关键字是r进制数(如十进制数),而r个数码在各位上出现的频率不一定相同,
    可能在某些位上分布均匀些
    每种数码出现的机会均等;而在某些位上分布不均匀,只有某几种数码经常出现,
    则应选取数码分布较为均匀
    的若干位作为散列地址。这种方法适合于已知的关键字集合

image-20240730142613377

手机号后四位分布比较均与 如果key为手机号那么取手机号后四位为散列值

4.平方取中法
顾名思义,取关键字的平方值的中间几位作为散列地址。具体取多少位要看实际情况而定。这种方法得
到的散列地址与关键字的每一位都有关系,使得散列地址分布比较均匀。

Eg

12342=1522756 取中间三位227作为散列地址

23452=5499025 取中间三位990作为散列地址

5.折叠法

将关键字分割成位数相同的几部分 (最后一部分的位数可以短一些),然后取这几部分的叠加和作为
散列地址,这种方法称为折叠法。关键字位数很多,而且关键字中每一位上数字分布大致均匀时,可
以采用折香法得到散列地址。
Eg:关键字为1234567890散列表表长为3位可以将关键字分为四组每组3位
123456|7890然后这四组叠加求和123+456+789+0=1368 然后取后3位就能得到散列地址为368

2.常用的Hash函数的冲突处理办法
1.开放定址法

​ :将产生冲突的Hash地址作为自变量,通过某种冲突解决函数得到一个新的空闲的Hash地址。

		1)   线性探测法: 冲突发生时,顺序查看表中下一个单元 (当探测到表尾地址m-1时,探测地址是表首地址0),直到找出一个空闲单元 (当表未填满时一定能找到一个空闲单元)或查遍全表。

image-20240730154952929

如上图,11 、19、27经过运算后的映射下标都是3,由于3被最开始的11占用,那19就不得不后移占住后面空着的下表,这样就会产生连锁反应导致原来hash值是4的key也要后移,这样查找起来就非常麻烦

比如我找27,先计算得出27的hash值是3,但发下3下面存的11,只能往后找4 – 19不是,继续遍历到5 – 17 找到了

2)平方探测法:设发生冲突的地址为d,平方探测法得到的新的地址序列为d+12,d-12,d+22,d-22
平方探测法是一种较好的处理冲突的方法,可以避免出现“堆积”问题,它的缺点是不能探测到散列
表上的所有单元,但至少能探测到一半单元。

image-20240730155513651

3)再散列法:又称为双散列法。需要使用两个散列函数,当通过第一个散列函数H(Key)得到的地址发
生冲突时,则利用第二个散列函数Hash2(Kev)计算该关键字的地址增量。

image-20240730155651274

4)伪随机序列法:当发生地址冲突时,地址增量为伪随机数序列,称为伪随机序列法。

2.拉链法:

对于不同的关键字可能会通过散列函数映射到同一地址,为了避免非同义词
发生冲突,可以把所有的同义词存储在一个线性链表中,这个线性链表由其散列地址唯
标识。拉链法适用于经常进行插入和删除的情况

3.散列表的查找过程

类似于构造散列表,给定一个关键字Key。
先根据散列函数计算出其散列地址。然后检查散列地址位置有没有关键字.
1)如果没有,表明该关键字不存在,返回查找失败。
2)如果有,则检查该记录是否等于关键字。

  • 如果等于关键字,返回查找成功。
  • 如果不等于,则按照给定的冲突处理办法来计算下一个散列地址,再用该地址去执行上述过程。
4.散列表的查找性能

性能和装填因子有关

什么是装填因子?

image-20240730160416593

image-20240730160759116

Golang中map的hash值是如何计算如何存的?

在日常编程中,map的底层也是hash表,但map 的 key 键不仅仅是数字,还可能是字符串。由于我们之前讨论的哈希函数主要是针对数字进行计算的,因此,当 key 为字符串时,首先需要将字符串转化为整数,然后再经过哈希函数的运算产生哈希值。

在 Go 中,map 的哈希值会通过取模运算(或其他方式)转换成哈希表中的一个具体位置,这个位置称为映射地址。映射地址通常对应于一个桶,桶是一个存储多个键值对的容器。每个桶可以存储多个键值对,以处理哈希冲突。桶的数量通常与哈希表的容量有关。

溢出桶:如果主桶已满,则会创建一个溢出桶,将多余的键值对存储在溢出桶中。如果溢出桶也满了,就会继续创建新的溢出桶,形成一个链表结构。

image-20240730161624131

ps:个人认为桶和线性链表及其相似

go map的扩容机制

扩容的时机装载因⼦超过⼀定的阈值或者使⽤了太多的溢出桶时。

扩容的规则:
  1. 等量扩容 使⽤溢出桶太多的时候会进⾏等量扩容。申请和原来等量的内容,将原来的数据重新整理

后,写⼊到新的内存中。可以简单的认为是⼀次内存整理,⽬的是提⾼查询效率。

  1. 增量扩容 分成两步: 第⼀步进⼊扩容状态,先申请⼀块新的内存,翻倍增加桶的数量,此时

buckets指向新分配的桶,oldbuckets指向原来的桶。 第⼆步,重新计算⽼的桶中的哈希值在新

的桶内的位置(取模或者位操作),将旧数据⽤渐进式的⽅式拷⻉到新的桶中。

渐进式迁移分两块,⼀⽅⾯会从第⼀个桶开始,顺序迁移每⼀个桶,如果下⼀个桶已经迁移,则跳

过。另⼀⽅⾯,当我们操作某⼀个桶的元素时,会迁移两个桶,进⽽保证经过⼀些操作后⼀定能够完

成迁移。

访问迁移的map时会放生什么?

当我们访问⼀个正在迁移的Map时,如果存在oldbuckets,那么直接去中oldbuckets寻找数据。当

我们遍历⼀个正在迁移的Map时,新的和旧的就会遍历,如果⼀个旧的的桶已经迁移⾛了,那么就直

接跳过,反正不在旧的就在新的⾥。Map遍历本⾝就是⽆序的。

定能够完

成迁移。

访问迁移的map时会放生什么?

当我们访问⼀个正在迁移的Map时,如果存在oldbuckets,那么直接去中oldbuckets寻找数据。当

我们遍历⼀个正在迁移的Map时,新的和旧的就会遍历,如果⼀个旧的的桶已经迁移⾛了,那么就直

接跳过,反正不在旧的就在新的⾥。Map遍历本⾝就是⽆序的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1960995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

平移、旋转、缩放和媒体

一、平移 1.1translate()函数 做转换工作可以用translate()函数,这个函数可以改变坐标系。通过改变默认的坐标系,我们可以创建不同的转换方式,包括平移、旋转和缩放。 1.2平移位置案例 案例代码如图1 图1 保存运行如…

【大一公共课】C语言+python语言入门对比+思维导图

C 和 Python 入门教程对比 一、引言 C 语言和 Python 语言都是在编程领域中广泛使用的语言,但它们在语法、应用场景和学习难度上有很大的不同。本教程将对 C 和 Python 的入门知识进行对比,帮助您更好地理解和选择适合自己的编程语言。 二、C 语言入门 …

python爬取某财富网

过程: 点击底部的第3页,第5页,网页刷新了,但是顶部的url地址没有变。那么就是 动态加载, 就是 XHR. 直接请求api. 实验代码如下: import requestsheaders {"User-Agent": "Mozilla/5.0 (Windows NT…

LLM大模型:2024工业AI大模型发展分析

一、大模型为工业智能化发展带来新机遇 1.1. 大模型开启人工智能应用新时代 大模型引领人工智能技术创新和应用。 自 1956 年达特茅斯会议(Dartmouth Conference)提出人工智能的概念以来,人工智能技术经历了多个发展高峰和低谷。在这一长期的…

《深入浅出WPF》学习笔记一.解析WPF程序

《深入浅出WPF》学习笔记一.解析WPF程序 visual studio帮助我们做了那些事情 引用文件 输出文件类型 按照最原始的方式,我们需要手动打开编译器命令行,使用命令引用类库将代码编译成目标文件。 visual studio会根据我们选择的项目模板,自动…

Java学习Day19:基础篇9

包 final 权限修饰符 代码块 静态代码块在Java中是一个重要的特性,它主要用于类的初始化操作,并且随着类的加载而执行,且只执行一次。静态代码块的实践应用广泛,以下是几个主要的应用场景: 1. 初始化静态变量 静态代…

芋道源码yudao-cloud 二开日记(Editor富文本本地图片上传报错问题)

: 于是找到富文本的组件代码Editor.vue,检查一下上传的接口地址和token有没有传,如下图: 都没有问题,但还是报错,所以试试自定义上传的方法: // 导入上传文件的接口 import * as FileApi from …

数字图像处理 --- 二维离散余弦变换(python实战)

二维离散余弦变换(python实战) (注:文中所讨论的离散余弦变换都是DCT-II) 在上一篇文章中,我详细介绍了一维离散余弦变换的基本原理,并且以可视化的方式展示了一维DCT中用于分析输入信号的一系列基础余弦波。 在这篇文…

【简单图解 最强计网八股】HTTP 和 HTTPS 的区别

HTTP(HyperText Transfer Protocol 超文本传输协议) HTTPS(Hypertext Transfer Protocol Secure,超文本传输安全协议) 通过 传输内容加密 和 身份认证 保证了传输过程的安全性 协议传输内容加密身份认证响应效率端口号…

​LLM大模型从入门到精通(7)--企业大模型开发流程​

一、大模型项目开发的两种方式 2023年以来,随着ChatGPT的火爆,使得LLM成为研究和应用的热点,但是市面上大部分LLM都存在一个共同的问题:模型都是基于过去的经验数据进行训练完成,无法获取最新的知识,以及各…

Axure中继器:数据动态展示的强大工具

在Axure RP这一强大的原型设计工具中,中继器(Repeater)无疑是一颗璀璨的明珠。它以其独特的功能和广泛的应用场景,成为设计师在创建数据密集型原型时的首选。本文将深入探讨Axure中继器的特点、使用方式及其在数据动态展示中的重要…

新手小白如何投放知乎信息流广告推广?

随着越来越多的企业开始寻求更有效的方式来触达目标客户,知乎作为一个集知识分享、社交互动于一体的平台,已经成为众多品牌青睐的广告投放渠道之一。特别是知乎的信息流广告,因其高度融合的内容形式和精准的目标用户定向,成为了品…

ReactHooks(完结)

上期戳here ReactHooks[三] 一.memo 函数1.1 语法格式 二. useMemo2.1 问题引入2.2 语法格式2.3 使用 useMemo 解决刚才的问题 三.useCallback3.1 useMemo和useCallback区别3.2 语法格式 四.useTransition4.1 问题引入4.2 语法格式4.3 使用 isPending 展示加载状态4.4 注意事项…

Python3 | 练气期,捕获错误异常 、自定义异常处理!

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] 0x00 前言简述 在我们开始学习 Python 编程语言的时候, 我们经常会遇到各种错误, 比如:语法错误,运行时错误,逻辑错误等等, 这些错误在开发学习中是不可避免的, 但是随着我们学习的深入可以发现 Python 可以很好的处理…

Java 8-函数式接口

目录 一、概述 二、 函数式接口作为方法的参数 三、函数式接口作为方法的返回值 四、 常用的函数式接口 简单总结 简单示例 4.1 Consumer接口 简单案例 自我练习 实际应用场景 多线程处理 4.2 Supplier接口 简单案例 自我练习 实际应用场景 配置管理 4.3 Func…

UCC5320SCDWVR驱动SIC的功耗计算

驱动功耗可以通过分析器件的电气特性和推荐的电源电压来估算。以下是一些关键信息,用于估算功耗: 电源电流: 输入电源静态电流(IVCC1​):最小值为1.67 mA,典型值为2.4 mA。输出电源静态电流&am…

day33

类类型接口 静态属性和静态方法 区分方法就是必须要有 new什么东西 完成什么类 第二种类类型接口 字面量类类型接口 接口继承 接口继承接口 继承多个接口 接口可以继承多个,但是类只能继承一个 接口不能继承对象 接口继承类,仅继承类中对于实…

力扣高频SQL 50题(基础版)第二十六题

文章目录 力扣高频SQL 50题(基础版)第二十六题1667.修复表中的名字题目说明实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题(基础版)第二十六题 1667.修复表中的名字 题目说明 表: Users ----------------…

Day7-指针专题二

1. 字符指针与字符串 C语言通过使用字符数组来处理字符串 通常,我们把char数据类型的指针变量称为字符指针变量。字符指针变量与字符数组有着密切关系,它也被用来处理字符串 初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串…

TCP/UDP通信

1、TCP/IP四层模型 TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP…