【数据结构】哈希表

目录

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) 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java集合面试宝典】HashMap的put流程和特性?HashMap的扩容机制?原理— day08

目录 数组和链表分别适用于什么场景&#xff0c;为什么&#xff1f; 数组 链表 List和Set的区别 List和Map、Set的区别 HashMap 、HashTable 和TreeMap有什么区别&#xff1f; hashmap的特性 HashMap和HashTable有什么区别&#xff1f;&#xff08;必会&#xff09; J…

【数据结构】树的介绍

文章目录前言树的概念及结构树的概念树的表示树在实际中的运用二叉树的概念及结构二叉树的概念现实中的二叉树特殊的二叉树二叉树的性质二叉树的储存结构顺序存储链式存储写在最后前言 &#x1f6a9;本章给大家介绍一下树。树的难度相对于前面的数据结构来说&#xff0c;又高了…

ESP32设备驱动-HDC1080温度湿度传感器驱动

HDC1080温度湿度传感器驱动 文章目录 HDC1080温度湿度传感器驱动1、HDC1080介绍2、硬件准备3、软件准备4、驱动实现1、HDC1080介绍 HDC1080 是一款集成温度传感器的数字湿度传感器,可在极低功耗下提供出色的测量精度。 HDC1080 在很宽的电源范围内工作,是一种低成本、低功耗…

“提效”|教你用ChatGPT玩数据

ChatGPT与数据分析&#xff08;二&#xff09; 上文给简单聊了一下为什么ChatGPT不能取代数据分析师&#xff0c;本文我们来深入感受一下如何让GPT帮助数据分析师“提效”。 场景一&#xff1a;SQL取数 背景&#xff1a;多数数据分析师都要用SQL语言从数据库中提取数据&#x…

ctfshow web入门 命令执行29-33

1.web29eval()函数是把所有字符串当作php代码去执行&#xff0c;这题过滤了flag,使用通配符绕过过滤应该要注意文件中没有重名的文件&#xff0c;或一部分是一样的文件payload:cecho%20nl flag.php; #官方解法&#xff0c;反引号表示执行系统命令&#xff0c;nl为linux系统命令…

springboot智慧外贸平台

053-springboot智慧外贸平台演示录像2022开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff…

干货:浅谈主数据管理项目建设思路

“主数据是数据之源&#xff0c;是数据资产管理的核心&#xff0c;是信息系统互联互通的基石&#xff0c;是信息化和数字化的重要基础。 ——《主数据管理实践白皮书》” 近期&#xff0c;国家印发《数字中国建设整体布局规划》&#xff0c;提出数字中国建设的整体框架…

I2C协议简介 Verilog实现

I2C协议 IIC 协议是三种最常用的串行通信协议&#xff08;I2C&#xff0c;SPI&#xff0c;UART&#xff09;之一&#xff0c;接口包含 SDA&#xff08;串行数据线&#xff09;和 SCL&#xff08;串行时钟线&#xff09;&#xff0c;均为双向端口。I2C 仅使用两根信号线&#xf…

Django 实现瀑布流

需求分析 现在是 "图片为王"的时代&#xff0c;在浏览一些网站时&#xff0c;经常会看到类似于这种满屏都是图片。图片大小不一&#xff0c;却按空间排列&#xff0c;就这是瀑布流布局。 以瀑布流形式布局&#xff0c;从数据库中取出图片每次取出等量&#xff08;7 …

Educational Codeforces Round 145 (Rated for Div. 2) (A~E)

Problem - B - Codeforces 思路&#xff1a; 我们选择长度后&#xff0c;其特定长度会构成一个正方形&#xff0c;因为点与点距离大于1&#xff0c;所以偶数的正方形里面只能包含偶数的正方形&#xff0c;奇数的包含奇数。计算每个长度容纳最大点数&#xff1a; 发现cnt[0]1,…

WPF毛笔字实现过程

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Python中生产者消费者模型

Python生产者消费者模型 一、消费模式 生产者消费者模式 是Controlnet网络中特有的一种传输数据的模式。用于两个CPU之间传输数据&#xff0c;即使是不同类型同一厂家的CPU也可以通过设置来使用。 二、传输原理 类似与点对点传送&#xff0c;又略有不同&#xff0c;一个生产…

能把爬虫讲的这么透彻的,没有20年功夫还真不行【0基础也能看懂】

前言 可以说很多人学编程&#xff0c;不玩点爬虫确实少了很多意思&#xff0c;不管是业余、接私活还是职业爬虫&#xff0c;爬虫世界确实挺精彩的。 今天来给大家浅谈一下爬虫&#xff0c;目的是让准备学爬虫或者刚开始起步的小伙伴们&#xff0c;对爬虫有一个更深更全的认知…

chatGPT爆火,什么时候中国能有自己的“ChatGPT“

目录 引言 一、ChatGPT爆火 二、中国何时能有自己的"ChatGPT" 三、为什么openai可以做出chatGPT? 四、结论 引言 随着人工智能技术的不断发展&#xff0c;自然语言处理技术也逐渐成为了研究的热点之一。其中&#xff0c;ChatGPT作为一项领先的自然语言处理技术…

【软件测试】基础知识第一篇

文章目录一. 什么是软件测试二. 测试和调试的区别三. 什么是测试用例四. 软件的生命周期五. 软件测试的生命周期一. 什么是软件测试 软件测试就是验证软件产品特性是否满足用户的需求。 那需求又是什么呢&#xff1f;在多数软件公司&#xff0c;会有两种需求&#xff0c;一种…

【vue3】小小入门介绍

⭐【前言】 首先&#xff0c;恭喜你打开了一个系统化的学习专栏&#xff0c;在这个vue专栏中&#xff0c;大家可以根据博主发布文章的时间顺序进行一个学习。博主vue专栏指南在这&#xff1a;vue专栏的学习指南 &#x1f973;博主&#xff1a;初映CY的前说(前端领域) &#x1f…

python自动发送邮件,qq邮箱、网易邮箱自动发送和回复

在python中&#xff0c;我们可以用程序来实现向别人的邮箱自动发送一封邮件&#xff0c;甚至可以定时&#xff0c;如每天8点钟准时给某人发送一封邮件。今天&#xff0c;我们就来学习一下&#xff0c;如何向qq邮箱&#xff0c;网易邮箱等发送邮件。 一、获取邮箱的SMTP授权码。…

new动态内库管理库学习

new文件是动态内存管理库的一部分&#xff0c;特别提供低层内存管理特性。 它包括bad_alloc, bad_array_new_length&#xff0c;nothrow_t&#xff0c;align_val_t类nothrow常量&#xff0c;以及函数 operator newoperator new[],operator deleteoperator delete[],get_new_han…

微信小程序登录注册页面

// login.js // 获取应用实例 var app getApp() var api require("../../utils/api.js")Page({data: {motto: zhenbei V1.0.0,userInfo: {},hasUserInfo: false,disabled: true,btnstate: default,username: ,password: ,canIUse: wx.canIUse(button.open-type.get…

Python实现人脸识别检测, 对美女主播照片进行评分排名

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 素材、视频、代码、插件安装教程我都准备好了&#xff0c;直接在文末名片自取就可点击此处跳转 开发环境: Python 3.8 Pycharm 2021.2 模块使用&#xff1a; requests >>> pip install requests tqdm >…