【数据结构】哈希表
目录
1、哈希表
1.1 哈希表的简介
1.2 降低哈希冲突率
1.3 解决哈希冲突
1.3.1 闭散列
1.3.2 开散列(哈希桶)
1、哈希表
1.1 哈希表的简介
假设我们目前有一组数据,我们要从这组数据中找到指定的 key 值,那么咱们目前的学习阶段可以利用三种方法:
- 把数据存储在数组当中,按顺序依次查找,时间复杂度为 O(n)
- 把数据存储在数组当中,此时数组有序,则可以用二分查找法,时间复杂度为 O(logn)
- 将其转化成搜索树进行查找,时间复杂度为 O(logn)
除了上述的查找方式以外,是否还有比上述查找方式的时间复杂度更优的呢?
答:有,还有一种方式可以做到查找时间复杂度为 O(1),这种方式就是用哈希表进行查找
哈希方法:通过某种函数使元素的存储位置与它的关键码(元素)之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素,不经过任何比较,一次直接从表中得到要搜索的元素
哈希函数和哈希表:哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表
- 插入操作:插入元素根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
- 搜索操作:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功
例如:假设我们现在有这样一种数据集合{1,6,7,5,4,9}
哈希函数设置为:hash = key % capacity
- hash:位置
- key :数据值
- capacity:数组长度
哈希表的长度为:10
假设我们现在要将第一个元素 1,放进哈希表中,首先通过哈希函数确定插入的位置 hash = 1%10那么此时 1 插入的位置也就是哈希表中下标为 1 的位置,其他元素也都是按照同样的方式进行存放到哈希表中
当我们进行搜索操作的时候也是通过哈希函数进行搜索的,假设我们现在需要查找 6 这个元素所在的位置,hash = key % capacity 也就是 6 % 10 = 6,此时 6 这个元素所在的位置就在 6 下标
假设我们目前需要在上述哈希表中插入 11 ,通过哈希函数找到的下标位置为 1,然后此时 1 下标的位置已经有值了,此时也就造成了哈希冲突问题了
哈希冲突:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞
哈希冲突产生的原因:由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一 个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率
1.2 降低哈希冲突率
那如何降低哈希冲突呢?
1.设计合理的哈希函数(哈希函数往往并不是由我们设计的,而是由专业人员进行设计的)
哈希函数设计原理:
- 哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1 之间 哈希函数计算出来的地址能均匀分布在整个空间中 哈希函数应该比较简单
- 哈希函数计算出来的地址能均匀分布在整个空间中
- 哈希函数应该比较简单
常见的哈希函数,目前咱们也就只介绍两个:
- 直接定制法:取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B。 优点:简单、均匀 缺点:需要事先知道关键字的分布情况 使用场景:适合查找比较小且连续的情况
- 除留余数法:设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数: Hash(key) = key% p(p<=m),将关键码转换成哈希地址
2.调节负载因子
负载因子 = 填入表中的元素个数 / 表的长度
负载因子的作用:
通过上述图就可以看出当负载因子越大时,冲突率也是越高的
那如何调节负载因子呢?
答:已知填入表中的元素个数是不变的,那么就只能调整哈希表的数组长度了。当数组长度越长,那么负载因子也就越小
一般情况下,哈希表会有一个默认的负载因子值为 0.75f
设计合理函数和调节负载因子也不能完全避免冲突 ,那么此时就可以解决哈希冲突
1.3 解决哈希冲突
解决哈希冲突常见的方法是:闭散列 和 开散列
1.3.1 闭散列
闭散列(开放地址法):当发生哈希冲突时,如何哈希表未被装满还有空余的位置,那么就可以将元素 key 存放到冲突位置中的 “下一个” 空位置中
那么我们应该如何找到下一个空位置呢?
方法一:线性探测法
线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止
插入:
- 通过哈希函数获取待插入元素在哈希表中的位置
- 如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到 下一个空位置,插入新元素
假设我们要在上述的哈希表中插入11,通过哈希函数确定的位置是下标 1,但是下标 1 的位置此时有元素发生了哈希冲突,使用线性探测找到的下一个空位置为下标2的位置,则把11 插入到下标2的位置
采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他 元素的搜索。比如删除元素1,如果直接删除掉,11查找起来可能会受影响。因此线性探测采用标 记的伪删除法来删除一个元素。
方法二:二次探测法
线性探测的缺陷是产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就是挨 着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法为:
假设我们现在需要在上述表中插入元素 11,通过哈希函数确定的位置是下标 1,但是下标 1 的位置此时有元素发生了哈希冲突,这是与 下标1 位置发生的第一次冲突:(11 + 1*1)% 10 = 2。那么此时元素 11 插入的位置就是下标2的位置
研究表明:当表的长度为质数且表装载因子a不超过0.5时,新的表项一定能够插入,而且任何一个位置都不 会被探查两次。因此只要表中有一半的空位置,就不会存在表满的问题。在搜索时可以不考虑表装满的情 况,但在插入时必须确保表的装载因子a不超过0.5,如果超出必须考虑增容
闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷
1.3.2 开散列(哈希桶)
开散列:开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中
- JDK1.7版本及以前每个桶使用的是头插法
- JDK1.8版本及以后每个桶使用的是尾插法
开散列可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了
那会不会哈希表中一个桶的长度太长,而导致搜索效率为 O(n)呢?
答:应该不会,因为有负载因子,当一个桶的长度太长时,会进行扩容
hashMap就是采用开散列的方式进行处理的, 当哈希表的长度到达64且桶的长度到底8时,会转换成红黑树
虽然哈希表一直在和冲突做斗争,但在实际使用过程中,我们认为哈希表的冲突率是不高的,冲突个数是可控的, 也就是每个桶中的链表的长度是一个常数,所以,通常意义下,我们认为哈希表的插入/删除/查找时间复杂度是 O(1)
相关文章:
【数据结构】哈希表
目录 1、哈希表 1.1 哈希表的简介 1.2 降低哈希冲突率 1.3 解决哈希冲突 1.3.1 闭散列 1.3.2 开散列(哈希桶) 1、哈希表 1.1 哈希表的简介 假设我们目前有一组数据,我们要从这组数据中找到指定的 key 值,那么咱们目…...
物联网常用协议MQTT协议相关介绍
概述 MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,旨在在网络带宽有限的情况下,为物联网设备之间的通信提供可靠的、低延迟的消息传递服务。MQTT协议具有订阅/发布模式,支持多种传输协议&a…...
【C语言进阶】13. 假期测评②
day10 1. int类型字节数 求函数返回值,传入 -1 ,则在64位机器上函数返回( ) int count 0; int x -1; while (x) {count;x x >> 1; } printf("%d", count);A: 1 B: 2 C: 32 D: 死循环,没结果 【答案解析】C xx&(x-1)这…...
【国产FPGA】国产FPGA搭建图像处理平台
最近收到了高云寄过来的FPGA板卡,下图:来源:https://wiki.sipeed.com/hardware/zh/tang/tang-primer-20k/primer-20k.htmlFPGA主要参数:FPGA型号参数GW2A-LV18PG256C8/I7逻辑单元(LUT4) 20736寄存器(FF) 15552分布式静态随机存储器S-SRAM(bit…...
你的应用太慢了,给我司带来了巨额损失,该怎么办
记得很久之前看过谷歌官方有这么样的声明:如果一个页面的加载时间从 1 秒增加到3 秒,那么用户跳出的概率将增加 32%。 但是早在 2012 年,亚马逊就计算出了,页面加载速度一旦下降一秒钟,每年就会损失 16 亿美元的销售额…...
第十四届蓝桥杯三月真题刷题训练——第 22 天
目录 第 1 题:受伤的皇后_dfs 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码: 思路: 第 2 题:完全平方数 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约…...
机器学习:朴素贝叶斯模型算法原理(含实战案例)
机器学习:朴素贝叶斯模型算法原理 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏&…...
Linux 多线程:理解线程
目录一、理解线程的思想二、Linux中的线程与进程1.Linux中的进程2.Linux中的线程三、线程的工作方式四、线程的独有数据与共享数据1.独有数据2.共享数据一、理解线程的思想 线程就是把一个进程分成多个执行部分,一个部分就是一个线程,比如可以让一个线程…...
Web前端学习:章四 -- JavaScript初级(四)-- BOM
138:Object数据格式简介 1、object对象 JS中独有 的一种数据格式 名字可以随便取,值一般就那几种数据格式 139:BOM - JS跳转页面 BOM Browser Object Model:浏览器对象模型 使用JavaScript控制浏览器交互 控制浏览器里面的内…...
Lesson9.网络基础1
网络协议初识 所谓的协议就是人们为了通信的一种约定 操作系统要进行协议管理,必然会先描述,再组织协议本质就是软件,软件是可以"分层"协议在设计的时候,就是被层状的划分的, 为什么要划分成为层状结构 场景复杂功能解耦(便于人们进行各种维护)OSI七层模型 局域网中…...
这几个SQL语法的坑,你踩过吗
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~ Github地址:https://github.com/…...
算法基础——复杂度
前言 算法是解决问题的一系列操作的集合。著名的计算机科学家Niklaus Wirth曾提出:算法数据结构程序,由此可见算法在编程中的重要地位。本篇主要讨论算法性能好坏的标准之一——复杂度。 1 复杂度概述 1.1 什么是复杂度 本文所讨论的复杂度是指通过事先…...
基类与派生类对象的关系 派生类的构造函数
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C 🔥座右铭:“不要等到什么都没有了,才下…...
【算法】生成分布式 ID 的雪花算法
ID 是数据的唯一、不变且不重复的标识,在查询数据库的数据时必须通过 ID 查询,在分布式环境下生成全局唯一的 ID 是一个重要问题。 雪花算法(snowflake)是一种生成分布式环境下全局唯一 ID 的算法,该算法由 Twitter 发…...
Linux系统编程 - 基础IO(IO操作)
目录 预备知识 复习C文件IO相关操作 printf相关函数 fprintf snprintf 读取文件 系统文件IO操作 open函数 umask()函数 open函数返回值 预备知识 1.你真的理解文件原理和操作了吗?不是语言问题,是系统问题2.是不是只有C/C有文件操作呢&#x…...
基于 Avue 的 CRUD 表格组件封装
在 components 文件夹中,创建一个新的 .vue 文件,例如:AvueCrudTable.vue。 透传父组件传递的属性和事件 : 1、利用v-bind=“ a t t r s " 支持所有 a v u e 的使用方法并在其基础上进行封装 2 、使用 v − o n = " attrs"支持所有 avue 的使用方法并在其基…...
树莓派学习笔记(十三)基于框架编写驱动代码
文章目录一、代码分析:二、源码一、代码分析: 在内核中由于代码文件多,避免函数名重复,使用static将函数的作用域限制在该文件内 内核的打印函数printk和printf类似 file_operations结构体使用符号“ . ”指定参数,省…...
vue事件修饰符之.prevent
.prevent 事件修饰符只是阻止默认事件,不会自动触发任何事件处理函数。因此,在使用 .prevent 事件修饰符时,需要自己编写相应的事件处理函数来处理事件。 例如,在上面的例子中,我们通过在表单上绑定 submit.prevent&q…...
【SpringCloud AlibabaSentinel实现熔断与限流】
本笔记内容为尚硅谷SpringCloud AlibabaSentinel部分 目录 一、Sentinel 1、官网 2、Sentinel是什么 3、下载 4、特性 5、使用 二、安装Sentinel控制台 1、sentinel组件由2部分构成 2、安装步骤 1.下载 2.运行命令 3.访问sentinel管理界面 三、初始化演示工程 …...
类与对象-封装
一、封装的意义封装是C面向对象三大特性之一语法: class name { 访问权限:属性行为 };注意:类中的属性和行为 统称为成员属性 又称 成员属性 / 成员变量行为 又称 成员函数 / 成员方法封装将属性和行为作为一个整体,表现生活中的事物例①&…...
【回忆杀】2012年拥有第一台电脑【致逝去的青春】
高中说起 在2012年的时候吧,高考过后,那个时候一门心思的想当一名体育老师【现在居然还有这个想法,哈哈】,最后没有考上自己希望的大学我记得好像是2012年7月的时候就去重庆投靠朋友,他教我做模具,2012年做…...
PointNeXt: Revisiting PointNet++ with Improved Training and Scaling Strategies
Abstract PointNet 是点云理解领域最有影响力的神经网络架构之一。虽然近期出现了 PointMLP 和 Point Transformer 等新型网络,它们的精度已经大大超过了 PointNet,但我们发现大部分性能提升是由于改进的训练策略,例如数据增强和优化技术以及…...
打印九九乘法表-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)
【案例2-9】打印九九乘法表 一、案例描述 考核知识点 for双重循环 练习目标 掌握for循环应用。实现九九乘法表。 需求分析 九九乘法表相信大家一点也不陌生,之前见到的乘法表是印刷在课程本之上的。而在本案例中我们将用JavaScript代码来实现九九乘法表。 案例分…...
【Linux】基于阻塞队列的生产者消费者模型
🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉为何要使用…...
【华为OD机试 2023最新 】 真正的密码(C++)
文章目录 题目描述输入描述输出描述用例题目解析C++题目描述 在一行中输入一个字符串数组,如果其中一个字符串的所有以索引0开头的子串在数组中都有,那么这个字符串就是潜在密码, 在所有潜在密码中最长的是真正的密码,如果有多个长度相同的真正的密码,那么取字典序最大的…...
差分算法(蓝桥杯复习+例题讲解+模板c++)
文章目录差分介绍差分应用区间加区间求和总结3729. 改变数组元素100. 增减序列文章首发于:My Blog 欢迎大佬们前来逛逛 差分介绍 差分是一种常见的算法,用于快速修改数组中某一段区间的值。 差分的思想就是预处理出数组的差分数组,然后修改…...
CSS+ JS 实现手电筒效果
前言概述 JavaScript 结合 CSS 打造的一款图片特效,当鼠标拖拽滑块时,让本该置灰的图片局部恢复本来的颜色。且该效果随着你的鼠标的按下时的移动而移动。 核心功能 图片置灰 拖拽功能 让滑块位置处的图片恢复本来的颜色 实现原理 这个的实现原理并不…...
2021地理设计组二等奖:基于InSAR和指数分析的地面沉降风
作品简介 一、作品背景 地面沉降是指地面高程的降低, 又称地面下沉或地沉, 是以缓慢、难以察觉的向下垂直运动为主, 是指在自然和人为因素作用下, 由于地壳表层土体压缩而导致区域性地面标高降低的一种环境现象。目前, 地面沉降己成为城市化进程中普遍存在的生态环境问题, 成为…...
计算机操作系统(第四版)第二章进程的描述与控制—课后习题答案
1.什么是前趋图?为什么要引入前趋图? 前趋图是一个有向无循环图,记为DAG,用于描述进程之间执行的先后关系。 2.试画出下面四条语句的前趋图: S1:axy; S2:bz1; S3:ca-b; S4:wc1; 3.为什么程序并发执行会产生间断性特征&…...
CAN通信----电路图
CAN通信----基本原理 一、CAN总线网络连接 1.闭环总线网络----ISO11898 闭环总线网络高速、短距离,它的总线最大长度为 40m,通信速度最高为 1Mbps,总线的两端各要求有一个120 欧的电阻。 2.开环总线网络----ISO11519 开环总线网络低速、…...
定制网站建设设计公司/seo系统培训班
什么是箱型图 箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。在各种领域也经常被使用,常见于品质管理。(来源:百度百科【箱型图】词条&…...
无锡品牌学会网站建设/百度浏览器网站入口
这边结合了当前大部分企业的通用需求,包括技术的选型比较严格、苛刻,不仅要用业界最流行的技术,还要和国际接轨,在未来的5~10年内不能out。作为公司的架构师,也要有一种放眼世界的眼光,不仅要给公司做好的技…...
网站怎么做充值系统下载/最新疫情19个城市封城
题目描述: 科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式[-][1-9]"."[0-9]E[-][0-9],即数字的整数部分只有1位,小数部分至少有1位,该数字及其指数部分的正负号即使对正数也…...
家电网站设计/泰安做网站公司
问题其他情况情况一情况二情况三总结问题 今日在练习SSM整合时,启动服务访问时遇见一个405异常 前端请求的方式是POST方式 后端页面响应使用的是请求转发 显式修改后端接收方式也不行 后将页面响应的改为重定向就可以了 其他情况 情况一 前端使用post方式…...
wordpress ux主题/免费个人网站建站
对于mesa的交叉编译。该文章的目标是编译一套aarch64 Linux Debian嵌入式版本上可以运行的版本库,接下来就开始趟坑。老套路,先把linux桌面版搞好,然后 移植到嵌入式Linux Debian 板子上。 1 mesa简介 Mesa 3D是一个在MIT许可证下开放源代码…...
网站建设的开多少税率/seo优化培训课程
问题: 给定一个栈,逆置栈中的内容,要求只能只用栈操作push和pop,不能用数组、栈、队列等做过渡。 基本思路: 用递归,先将原来栈中的元素递归出栈,直至栈为空,然后在每次递归向上步…...