什么是哈希冲突?如何解决哈希冲突?HashMap和TreeMap之间的区别?

Map 和 Set 的概念

Map和Set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关 。

为什么说它是一种专门用来进行搜索的数据结构呢?

我们应该都用过“遍历查找”、“二分查找”,这两种方式也都是用来对目标值进行搜索的,但是,这两种方式有些缺陷:

遍历查找需要一个一个的遍历,时间复杂度达到了O(N),比较消耗时间。

二分查找的时间复杂度是log(N),但是,二分查找的前提是,查找的元素必须是有序的。

例如在生活中,我们可能会通过学生的名字查找成绩,在通讯录中,通过名字查找电话号等场景,显然上述的查找方法就实现不了。

两种接口对应的模型

Map 和 Set 是两种不同的搜索模型,分别是 Key - Value 模型,纯 Key 模型

Key - Value 模型:一般要搜索的数据称为关键字(Key),和关键字相对应的称为值(Value)

例如:通过学生的名字查找对应的考试成绩,学生的名字就是Key,考试成绩就是Value。

纯 Key 模型:只含有 Key ,没有对应的 Value 值

例如:我想要快速的查找某个学生在这个班级中。

Map 的常用实现类:HashMap、TreeMap

Set 的常用实现类:HashSet、TreeSet

TreeMap 和 TreeSet 底层是搜索树

HashMap 和 HashSet 底层是哈希表

下面,来讲解一下 TreeMap 和 HashMap。

Map

Map是一个接口类,该类没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不能重复。

Map 中的一些常用方法

方法解释
V get(Object key)返回 key 对应的 value
V getOrDefault(Object Key, V defaultValue)返回 key 对应的 value,如果 key 不存在,则返回默认值
V put(K key, V value)设置 key 对应的 value
V remove(Object key)删除 key 对应的映射关系
Set < K > keySet()返回所有 Key 的不重复集合
Collection< V > values()返回所有 value 的可重复集合
Set<Map.Entry<K,V>> entrySet()返回所有的 key-value 映射关系
boolean containsKey(Object key)判断是否包含 key
boolean containsValue(Object value)判断是否包含 value

Map.Entry<k, V>

**Map 是如何来存储 <K,V> 结构的键值对的呢?**Map 是通过 Map.Entry<K , V>进行存储的。

Map.Entry<K, V> 是 Map 内部定义了一个用来存放 <key, value> 键值对的内部接口,该接口种主要提供了 <key, value> 的获取,value 的设置以及key的比较方式。(这一点可以通过源码去查看)。

Map.Entry<K, V> 接口种的一些常用方法:

方法解释
K getKey()返回 Entry 中的key
V getValue()返回 Entry 中的 value
V setValue(V value)将键值对中的value替换成指定的value

TreeMap

TreeMap 是 Map 的一个实现类,底层结构是 “搜索树(红黑树)”,而搜**索树的性质是:左子树上的所有节点比根节点小,右子树上的所有节点都比根节点大,**所以,**每当向这个搜索树上添加一个元素时,都需要进行比较,**在上面也讲了,Map 是用 Map.Entry<K, V>,来存储键值对的,所以,搜索树上的每个元素都是一个 Map.Entry<K, V>,而在进行比较时,是根据 Map.Entry<K, V> 中的 key 进行比较的,这一点在源码中也可以看到。而且,在获取这个搜索树上的所有key时,还会对所有的key进行一个排序,如下代码:

        Map<String, Integer> map = new TreeMap<>();map.put("ggg", 3);map.put("ccc",2);map.put("aaa", 1);Set<Map.Entry<String, Integer>> entries = map.entrySet();for(Map.Entry e : entries) {//获取所有的KeySystem.out.println(e.getKey());}

在这里插入图片描述

总结:

  1. Map 是一个接口,不能直接实例化对象,只能实例化它的实现类 TreeMap 或者 HashMap 等
  2. Map 中存放键值对的key是唯一的,value 是可以重复的。
  3. 在 TreeMap 中插入键值对时,key 不能为空,否则就会抛 NullPointerException 异常,因为,它需要使用key进行比较,value 可以为空.
  4. Map 中的key可以全部分离出来,存储到Set中进行访问。
  5. Map中的value可以全部分离出来,存储到Collection的任意一个集合中。

HashMap

顺序结构以及平衡树中,元素关键码(key)与元素存储的位置之间没有对应的关系,意思就是:如果要找某一个key时,需要使用key进行多次比较来查找,而顺序结构的时间复杂度时O(n),平衡树的时间复杂度为树的高度O(logN),搜索效率取决于搜索过程中元素的比较次数。而哈希表就对搜索效率进行了优化。

哈希表:通过某种函数使元素的存储位置与它的关键码key之间能够建立一一映射的关系。

所以:

插入元素时:

根据待插入元素的关键码key,通过此函数计算出该元素的存储位置,然后进行存储。

搜索元素时:

根据待搜索元素的关键码key,按照同样的函数计算出元素的存储位置,然后就可以快速的查到该元素。

这种存储的方式就称为:哈希方法,哈希方法中使用的函数就是哈希函数,构造出来的结构就称为哈希表。

如下图:

在这里插入图片描述

哈希冲突

什么是哈希冲突?

哈希冲突:当多个不同的关键字key通过相同的哈希算法所计算出相同的哈希地址,称为哈希冲突。

如下图:

当通过相同的哈希算法计算44的哈希地址时,44的哈希地址就和4的哈希地址冲突了。

在这里插入图片描述

哈希冲突避免

当key值越来越多时,冲突的必然会发生的,就要想办法尽量去避免冲突,如以下两种方式:

哈希函数的设计

直接定制法,除留余数法,平方取中法等。

负载因子调节

散列表的载荷因子定义为:α = 填入表中的元素个数 / 散列表的长度

α 表示散列表装满程度的标志因子,由于散列表的长度是定值,α 与 填入表中的元素成正比,所以,α 越大,表示填入表中的元素越多,产生冲突的可能性就越大,反之,α越小,表示填入表中的元素就越少,产生冲突的可能性就越低,所以,Java限制了载荷因子为0.75,当 α 超过 0.75 时,散列表的长度就进行扩大。

哈希冲突的解决

解决哈希冲突的方法主要有两种:

  • 闭散列
  • 开散列

注意:哈希冲突是无法解决的,冲突是必然会发生的,这里说的解决冲突,意思是当冲突发生时,把当前发生的冲突现象给解决了,并不是说能够彻底性的解决冲突。

闭散列

闭散列:闭散列也叫开放地址法,当发生哈希冲突时,如果哈希表中还有空位置的话,就把当前 key 放在发生冲突位置的下一个位置上。那么如何寻找下一个位置呢???有两种方法:

  1. 线性探测

如下图:

当44和4发生冲突后,就会从4下标的位置向后寻找空位置,当找到空位置后,就进行存储。

在这里插入图片描述

但是,这种方式有一些缺陷:

  1. 发生冲突的元素堆积在了一块,因为发生冲突的元素会一直向后寻找空位置及进行存储。

  2. 当采用这种方式解决哈希冲突时,不能随便的物理删除哈希表中存在的元素,否则的话,就会影响其他元素的搜索,例如上图,如果删除了4,那么44查找起来就会收到影响。因此,线性探测采用的对要删除的元素进行标记的伪删除法。

  3. 二次探测

上述的线性探测容易造成冲突元素的堆积以及不能随便的物理删除哈希表中的元素,而二次探测就对这样的缺陷进行了改善,如下图:

在这里插入图片描述

研究表明:当表的长度为质数且表的负载因子α不超过0.5时,新的元素已经能够插入,而且任何一个位置都不会别探查两次,因此,只要表中有一半的空位置,就不会存在装满的问题,在搜索时可以不考虑装满的情况,但是在插入时,必须保证表的负载因子α不超过0.5,如果超过,就必须考虑增容。因此,闭散列最大的缺陷就是空间利用率低,这也是哈希的缺陷。

开散列(哈希桶)

开散列又称为链地址法,通过哈希函数对关键码计算出哈希地址,具有相同地址的关键码放在同一个集合中,这个集合就称为桶,再使用链表将桶中的元素给串联起来,链表的头节点存放在哈希表中,当查找某一个元素时,通过哈希地址再得到具体的位置,然后再对链表进行遍历查找,如下图:

在这里插入图片描述

HashMap 和 TreeMap 之间的区别

TreeMapHashMap
底层结构红黑树哈希桶
插入/删除/查找 时间复杂度O(logN)O(1)
是否有序关于Key有序无序
线程安全不安全不安全
插入/删除/查找 的区别需要通过元素比较通过哈希函数计算哈希地址
比较及重写必须能够进行比较,如果是自定义类型,必须重写equeals()方法自定义类型需要重写equals() 和 hashcode() 方法
应用场景需要key有序的情况下需要更高的查询效率场景下

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

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

相关文章

Spring Security系列之PasswordEncoder

概述 任何一个登录系统的密码不能明文存储&#xff0c;万一发生数据库泄漏事故&#xff08;不管是内部人员导出数据库数据还是被黑客攻击破解数据库实例节点拿到数据库数据等&#xff0c;又或者是其他情况造成的&#xff09;&#xff0c;将产生巨大的损失。因此明文密码在存储…

DOS 操作系统

DOS 介绍 DOS&#xff1a;disk operating system&#xff0c;磁盘操作系统。 中国DOS联盟下载 MS-DOS 7.10完整安装版&#xff08;含图形安装程序&#xff09; DOS 环境下的操作 输入部分内容后按下 Tab 可以快速自动补全。 按住 Ctrl 键可以用鼠标滚轮改变字号大小。 DO…

【数据结构初阶】--- 顺序表

顺序表&#xff0c;好像学C语言时从来没听过&#xff0c;实际上就是给数组穿了层衣服&#xff0c;本质是一模一样的。 这里的顺序表实际是定义了一个结构体&#xff0c;设计各种函数来实现它的功能&#xff0c;比如说数组中的增删改查插入&#xff0c;这些基本操作其实平时就会…

Log4j日志级别介绍

Log4j 是一个广泛使用的 Java 日志记录框架&#xff0c;提供了多种日志级别&#xff0c;用于控制日志输出的详细程度。每个日志级别代表一种特定的重要性和紧急程度。 以下是 Log4j 的常见日志级别及其解读&#xff1a; FATAL&#xff08;致命&#xff09; 解释&#xff1a;表…

【报错解决】深度学习模型训练时cuda内存足够但测试时反而报错cuda out of memory

报错描述 报错的代码如下&#xff1a; model reader(configargs, encoderencoder)#初始化模型 model.to(cuda)#把模型放到gpu上 model.load_state_dict(torch.load(join(args.checkpoint_path, best_ckpt_model1.pkl)))#加载模型参数 model torch.nn.DataParallel(model)#并…

c++调用动态库LNK2019无法解析的外部符号LNK1120无法解析的外部命令

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK1120 6 个无法解析的外部命令 ConsoleApplication1 D:\vs_qt_project\ConsoleApplication1\x64\Debug\ConsoleApplication1.exe 1 严重性 代码 说明 项目 文件 行 …

聊聊App在安卓设备中所使用的内存

文章用来记录及分享本人对安卓程序中内存使用的个人见解&#xff0c;如有不同见解 不吝赐教。 先简单浏览下面代码&#xff0c;看看对它们是否熟悉&#x1f447; val activityManager getSystemService(ACTIVITY_SERVICE) as ActivityManager// Java 堆内存信息val runtime R…

adb 脚本化Android系统截图和录屏

1、首先我们了解截图和录屏最基础的命令 手机录屏 adb shell screenrecord sdcard/Pictures/Screenshots/Record_xxx.mp4导出手机录屏 adb pull sdcard/Pictures/Screenshots/Record_xxx.mp4手机截屏 adb shell screencap /sdcard/Screenshots_xxx.png导出手机截屏 adb pu…

应用层——HTTP协议(自己实现一个http协议)——客户端(浏览器)的请求做反序列化和请求分析,然后创建http向响应结构

应用层&#xff1a;之前我们写的创建套接字&#xff0c;发送数据&#xff0c;序列化反序列化这些都是在写应用层 我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层 之前的网络计算机是我们自定义的协议&#xff1a;传输的数据最终是什么样的结…

Gnu/Linux 系统编程 - 如何获取帮助及一个演示

Gnu/Linux 系统编程 - 如何获取帮助及一个演示 今天开始写 Gnu/Linux 环境下的系统编程&#xff0c;主要的用的语言是 C&#xff0c;主要是为了学习 C 语言&#xff0c;边学边写&#xff0c;这样的学习速度是比较快的。 今天就先介绍下如何在手头上没有任何资料的情况下&…

windows11搭建 stable-diffusion-webui

2024年5月22日23:46:57 建议电脑配置 电脑配置&#xff1a; Intel Core™ Ultra 5 125H 1.20 GHz 32.0 GB (31.6 GB 可用) 系统&#xff1a;windows11 注意&#xff1a;最好挂上外网&#xff0c;或者设置好访问github的dns&#xff0c;不然很可能失败 1&#xff0c;安装 An…

高级文件操作

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Python内置的os模块除了可以对目录进行操作&#xff0c;还可以对文件进行一些高级操作&#xff0c;具体函数如表4所示。 表4 os模块提供的与文件相…

vue3 项目目录使用文件夹和index.vue,与直接用直接用名字.vue的区别

在 Vue 3 项目中&#xff0c;使用文件夹加 index.vue 文件与直接使用组件名字命名的 .vue 文件都是常见的组织方式。两者各有优缺点&#xff0c;适用于不同的场景和需求。以下是对这两种方式的详细比较&#xff1a; 使用文件夹和 index.vue 文件 结构示例 src/ ├── compo…

【AI基础】第三步:纯天然保姆喂饭级-安装并运行chatglm2-6b

chatglm2构建时使用了RUST&#xff0c;所以在安装chatglm2之前&#xff0c;先安装RUST。 此系列文章列表&#xff1a; 【AI基础】第一步&#xff1a;安装python开发环境-windows篇_下载安装ai环境python-CSDN博客 【AI基础】第一步&#xff1a;安装python开发环境-conda篇_mini…

知识图谱的应用---智慧司法

文章目录 智慧司法典型应用 智慧司法 智慧司法是综合运用人工智能、大数据、互联网、物联网、云计算等信息技术手段&#xff0c;遵循司法公开、公平、公正的原则&#xff0c;与司法领域业务知识经验深度融合&#xff0c;使司法机关在审判、检查、侦查、监管职能各方面得到全面的…

Android14 WMS-Power键短按流程

目录 1. PhoneWindowManager#interceptKeyBeforeQueueing 2. PhoneWindowManager#handleKeyGesture 3. PhoneWindowManager#handleCameraGesture 4. SingleKeyGestureDetector#interceptKey 5. SingleKeyGestureDetector#interceptKeyUp 6. SingleKeyGestureDetector#Ke…

【数据结构】图论入门

引入 数据的逻辑结构&#xff1a; 集合&#xff1a;数据元素间除“同属于一个集合”外&#xff0c;无其他关系线性结构&#xff1a;一个对多个&#xff0c;例如&#xff1a;线性表、栈、队列树形结构&#xff1a;一个对多个&#xff0c;例如&#xff1a;树图形结构&#xff1…

「前端+鸿蒙」鸿蒙应用开发-搭建开发环境创建项目

快速体验鸿蒙应用开发&#xff0c;首先需要搭建开发环境和创建项目。 搭建开发环境 下载DevEco Studio&#xff1a; 访问华为开发者联盟官方网站下载DevEco Studio。DevEco Studio下载链接 安装DevEco Studio&#xff1a; 运行下载的安装程序&#xff0c;按照安装向导指引完成…

SpringBoot中的WebMvcConfigurationSupport和WebMvcConfigurer

在SpringBoot中可以通过以下两种方式来完成自定义WebMvc的配置&#xff1a; &#xff08;1&#xff09;继承WebMvcConfigurationSupport类 &#xff08;2&#xff09;实现WebMvcConfigurer接口 通过这两种方式完成的WebMvc配置存在差异&#xff0c;本文将对此作简单说明与区…

【Vue】单页应用程序介绍

通常基于Vue去开发一整个网站&#xff0c;开发出来的这整个网站应用&#xff0c;我们都会叫做单页应用程序 概念 单页应用程序&#xff1a;SPA【Single Page Application】是指所有的功能都在一个html页面上实现 我们可以将页面共用的部分封装成组件&#xff0c;底下要切换的也…