什么是哈希表(HashTable)?

news2024/10/5 22:37:04

目录

一、概念

二、哈希冲突

减少哈希冲突的办法:

1、设计合理的哈希函数

哈希函数设计原则:

常用的哈希函数:        

2、降低负载因子(必须重点掌握)

哈希冲突的解决

第一类:闭散列

第二类:开散列/哈希桶(重点掌握)


一、概念

我们在初学数据结构时,接触了许多的搜索方式,但是搜索效率最高的也只有O(logN),比如说二分查找。有时我就不经幻想,是否有一种方法,可以让搜索效率达到恐怖的O(1)呢?我以为在白日做梦,唉,没想到还真有,没错就是今天要讲的哈希表

既然它那么厉害,说明它的搜索方式就不走寻常路,举个例子,来大致理解一下它的原理,以数据集合{1,7,6,4,5,9}为例:

首先要把待搜索元素集合,放到哈希表(一种特别的“数组”)中:

红色的是数字数据集合中的6个元素,看起来,这6个元素放的很乱,但实际上,他们是按照一个特定的规则去存放的

每个待存放元素的值,我们称为关键码,关键码通过哈希函数的计算得到一个哈希表的存放位置下标(就是数组的下标)。

For example:元素“6”,把6带入哈希函数,返回的值是6,那么就把元素6放到哈希表的数组中的6下标位置。

在所有元素存完后,如果要搜索某一个元素,只需要获取改元素的关键码,通过哈希函数,计算出哈希表相应位置,判断是否有此元素即可。

比如我要查询元素“3”是否存在

假设元素“3”(元素值就是关键码)通过哈希函数计算,哈希函数返回了2下标,我们就去2下标,寻找,发现2下标没有元素存放,所以没有找到。


注意:

有时候,我们要查询的元素,不一定是简单类型int,这时候需要用到java中hashCode()方法获取一个关键码,然后再用哈希函数计算下标值。

关于哈希函数

一般哈希函数:hash(key) = key % capacity

hash就是底层数组的下标了

key是元素的关键码

capacity是储存底层元素的空间容量大小

如图:

用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度非常快。

当然这也是有代价的,属于使用空间效率换取时间效率,毕竟世界上很难有十全十美的东西。

按照上述的思考逻辑,来思考一下,如果往这个集合中插入元素“66”,会怎么样?

二、哈希冲突

如果插入元素“66”,我们发现这个哈希表(数组),就出现问题了,因为通过哈希函数计算,下下标应该是6,但是下标为6的位置已经存储了一个元素了。

这实际上就叫做哈希冲突

此时,我们在用关键码,借助哈希函数计算出下标的位置,就可能出错了,因为同一个下标,不同的元素,计算出来的下标可能会出现一样的情况,无法做到11对应,就无法正确的搜索

减少哈希冲突的办法:

首先先,我们需要明确一点,由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一 个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率

有些同学可能会想,那一定会冲突,冲突了怎么办?

这个问题等一下会有解决办法,我们先不急,等一下会讲,先把降低冲突率的方法讲完。

1、设计合理的哈希函数

哈希函数设计原则:

第一点:哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1 之间

第二点:哈希函数计算出来的地址能均匀分布在整个空间中(这是为什么叫散列表的原因)

第三点:哈希函数应该比较简单

常用的哈希函数:        

第一个方法----直接定制法--(常用)

取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B

优点:简单、均匀 缺点:需要事先知道关 键字的分布情况

使用场景:适合查找比较小且连续的情况

第二个方法----除留余数法--(常用)

设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数: Hash(key) = key% p(p<=m),将关键码转换成哈希地址


2、降低负载因子(必须重点掌握)

负载因子和冲突率的粗略关系:

从公式中我们直到,要降低负载因子,就只能去扩大散列表的长度了(因为表中的元素不可更改,你不能让别人不存东西吧)

也就是说,在负载因子达到某个值时,就要考虑给数组扩容了。

哈希冲突的解决

第一类:闭散列

也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以 把key存放到冲突位置中的“下一个” 空位置中去。

方式有线性探测二次探测,不用重点掌握。

比散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷。
因为他要把冲突的元素放到另一个位置,而这个位置又要尽可能分散。因此,时不时需要扩容。

第二类:开散列/哈希桶(重点掌握

如图,若我们还想放一个“44”,将会出现哈希冲突:

闭散列想的是,把44放到空的位置。

而开散列,将计就计,也把他放到,下标为4的位置。

怎么放呢很简单。

先前这个数组,只是一个简单的数组,每个元素,存放的都是int型。

现在我们不储存int型元素,而是储存链表的头结点:

此时,想要存“44”就简单了,直接在4下标出,把val=44的节点,头插或者尾插(jdk1.8之后底层使用的尾插法)进链表即可。

有些同学可能会有疑问,不是说哈希表的搜索效率是O(1)吗?

如果要找到相应的元素,最终不是还要遍历链表?

回答:

首先,在哈希表中,当负载因子达到某个值时,会自动扩容,降低冲突概率,冲突概率本身就很低,绝大部分情况下链表长度并不大。

其次,当链表的长度的确变得很大时,哈希表还会对这个链表进行优化--(把链表转化为一个红黑树((底层就是搜索树))

实际上,这才是真正的哈希表,(由多个哈希桶组成的--哈希桶就是上面所说的链表,或者红黑树)


哈希表是一个很重要的数据结构,不论是Map还是Set实际上底层都是哈希表实现的。

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

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

相关文章

实时监控RTSP视频流并通过YOLOv5-seg进行智能分析处理

在完成RTSP推流之后&#xff0c;尝试通过开发板接收的视频流数据进行目标检测&#xff0c;编写了一个shell脚本实现该功能&#xff0c;关于视频推流和rknn模型的部署请看之前的内容或者参考官方的文档。 #!/bin/bash # 设置脚本使用的shell解释器为bashSEGMENT_DIR"./seg…

【模板】前缀和

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 前缀和模板题。 前缀和中数组下标为1~n。 前缀和&#xff1a;pre[i]pre[i-1]a[i]; 某段区间 [l,r]的和&#xff1a;pre[r]-pre[l-1] 3.…

【数学建模】2024五一数学建模C题完整论文代码更新

最新更新&#xff1a;2024五一数学建模C题 煤矿深部开采冲击地压危险预测&#xff1a;建立基于多域特征融合与时间序列分解的信号检测与区间识别模型完整论文已更新 2024五一数学建模题完整代码和成品论文获取↓↓↓↓↓ https://www.yuque.com/u42168770/qv6z0d/gyoz9ou5upv…

unity制作app(2)--主界面

1.先跳转过来&#xff0c;做一个空壳&#xff01;新增场景main为4号场景&#xff01; 2.登录成功跳转到四号场景&#xff01; 2.在main场景中新建canvas&#xff0c;不同的状态计划用不同的panel来设计&#xff01; 增加canvas和底图image 3.突然输不出来中文了&#xff0c;浪…

【19-文本数据处理:Scikit-learn中的自然语言处理技术】

文章目录 前言理解文本数据文本预处理文本清洗分词停用词去除向量化文本数据词袋模型TF-IDF变换构建文本分类模型模型评估与调优结论前言 欢迎回到我们的Scikit-learn系列,在这篇文章中,我们将探讨如何使用Scikit-learn来处理文本数据,这是自然语言处理(NLP)的基础。你将学…

为家庭公网IP配置DDNS域名

文章目录 域名配置域名更新frp配置修改 在成功完成frp改造Windows笔记本实现家庭版免费内网穿透之后&#xff0c;某天我突然发现内网穿透失效了&#xff0c;一番排查之后原来是路由器对应的公网IP更换了。果然我分到的并不是固定的公网IP&#xff0c;而是会定期变化的。为了免受…

中间件之异步通讯组件RabbitMQ入门

一、概述 微服务一旦拆分&#xff0c;必然涉及到服务之间的相互调用&#xff0c;目前我们服务之间调用采用的都是基于OpenFeign的调用。这种调用中&#xff0c;调用者发起请求后需要等待服务提供者执行业务返回结果后&#xff0c;才能继续执行后面的业务。也就是说调用者在调用…

解决IDEA下springboot项目打包没有主清单属性

1.问题出现在SpringBoot学习中 , 运行maven打包后无法运行 报错为spring_boot01_Demo-0.0.1-SNAPSHOT.jar中没有主清单属性 SpringBoot版本为 2.6.13 Java 版本用的8 解决方法 1.执行clean 删除之前的打包 2.进行打包规范设置 2.1 3.进行问题解决 (借鉴了阿里开发社区) 使用…

OpenCV(二)—— 车牌定位

从本篇文章开始我们进入 OpenCV 的 Demo 实战。首先&#xff0c;我们会用接下来的三篇文章介绍车牌识别 Demo。 1、概述 识别图片中的车牌号码需要经过三步&#xff1a; 车牌定位&#xff1a;从整张图片中识别出牌照&#xff0c;主要操作包括对原图进行预处理、把车牌从整图…

碳纤维复合材料的纳米纤维膜

碳纤维复合材料的纳米纤维膜是一种具有良好性能和应用前景的新材料。以下是关于这种材料的详细介绍&#xff1a; 制备方法&#xff1a;碳纤维复合材料的纳米纤维膜可以通过多种方法制备&#xff0c;包括化学气相沉积法、固相合成法、模板法等。其中&#xff0c;化学气相沉积法是…

Docker——部署LNMP架构

目录 一、LNMP架构概述 1.项目环境 2.服务器环境 3.需求 二、搭建Linux系统基础镜像 三、部署Nginx 1.建立工作目录 2.编写Dockerfile脚本 3.准备Nginx.conf配置文件 4.生成镜像 5.创建自定义网络 6.启动镜像容器 7.验证Nginx 三、部署Mysql 1.建立工作目录 2.编…

MathType打开的窗口太多 MathType说打开窗口太多无法复制怎么解决

在数学文档编辑中&#xff0c;MathType作为一款常用的数学公式编辑工具&#xff0c;使用过程中&#xff0c;我们常常会遇到一些问题&#xff0c;比如MathType打开的窗口过多导致软件运行缓慢甚至崩溃&#xff0c;以及在复制过程中出现“打开窗口太多&#xff0c;无法复制”的提…

2024年教你怎么将学浪视频保存到本地

你是否曾为无法将学浪视频保存到本地而烦恼&#xff1f;现在&#xff0c;我们将在2024年教给你如何解决这个问题&#xff01;只需简单几步操作&#xff0c;即可轻松将学浪视频保存到您的本地设备&#xff0c;随时随地想看就看&#xff01; 我已经将下载学浪的工具打包好了&…

使用FPGA实现并行乘法器

介绍 并行乘法器&#xff0c;那么它的输入输出就都是并行的数据了&#xff0c;相对来说&#xff0c;内部的结构就更复杂了&#xff0c;占用的资源就更多了。以后有需要完成这部分操作的话都可以调用IP核。 乘法器模块 这是一个纯组合逻辑电路&#xff0c;我们也知道&#xff0…

C++--const成员及const取地址操作符重载

前言 今天我们来了解一下const成员的基本使用,以及const取地址重载的运用 来开始今天的学习 const成员 1.基本定义, 将const修饰的“成员函数”称之为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际修饰该成员函数 隐含的*this指针&#xff0c;表明在该成员函…

队列以及信号量

什么是队列 队列又称消息队列&#xff0c;是一种常用于任务间通信的数据结构&#xff0c;队列可以在任务与任务间、中断和任 务间传递信息。 为什么不使用全局变量&#xff1f; 如果使用全局变量&#xff0c;兔子&#xff08;任务1&#xff09;修改了变量 a &#xff0c;等待树…

LeetCode LCR 179. 和为s的两个数字

原题链接&#xff1a;LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 题目的意思&#xff1a;通过给定的数组&#xff0c;找出两个值&#xff0c;相加并等于目标值。 第一种思路&#xff0c;暴力枚举&#xff0c;伪代码如下&#xff1a; for (…

【Linux】详解信号的保存信号屏蔽字的设置

一、信号处理的一些常见概念 实际执行信号的处理动作称为信号递达(Delivery)。信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞 (block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意&#xff1a;阻…

传感器测试脉冲电源 —测试传感器性能的电源设备

传感器测试脉冲电源是一种专门用于测试传感器性能的电源设备。传感器测试脉冲电源可以输出不同幅值、频率和形状的脉冲信号&#xff0c;以模拟传感器在实际应用中可能遇到的各种电压和电流波形。通过这种电源&#xff0c;可以对传感器进行全面的性能测试&#xff0c;包括动态响…

信号,信号列表,信号产生方式,信号处理方式

什么是信号 信号在我们的生活中非常常见&#xff1b;如红绿灯&#xff0c;下课铃&#xff0c;游戏团战信号&#xff0c;这些都是信号&#xff1b;信号用来提示接收信号者行动&#xff0c;但接收信号的人接收到信号会进行一系列的行为&#xff0c;完成某个动作&#xff1b;这就…