【Java】HashMap 背诵版

news2024/11/16 3:35:01

HashMap 背诵版

  • 1. HashMap、Hashtable 和 ConcurrentHashMap 的区别?
    • 1.1 线程安全:
    • 1.2 继承关系:
    • 1.3 允不允许null值:
  • 2. HashMap 的数据结构
    • 2.1 什么是hash表?
    • 2.2 HashMap 的数据结构
  • 3. 什么是hash冲突,怎么解决?
    • 3.1 什么是hash冲突?
    • 3.2 为什么不能完全避免hash冲突?
    • 3.2 hash冲突怎么解决?
      • (1)开放定址法(再散列法)
      • (2)再哈希法
      • (3)建立公共溢出区
      • (4)链地址法
  • 4. 为什么在 JDK8 中 HashMap 要转成红黑树?
    • 4.1 为什么不继续使用链表?
    • 4.2 为什么是红黑树?
      • (1)二叉树
      • (2)二叉平衡树
      • (3)红黑树(自平衡二叉查找树)

1. HashMap、Hashtable 和 ConcurrentHashMap 的区别?

1.1 线程安全:

HashMap 是非线程安全的。

Hashtable 中的方法是同步的,所以它是线程安全的。

ConcurrentHashMap 在 JDK1.8 之前,使用分段锁以在保证线程安全的同时获得更大的效率。JDK1.8 开始舍弃了分段锁,使用 自旋 + CAS + synchronized 来实现同步。官方的解释中:一是节省内存空间 ,二是分段锁需要更多的内存空间,而大多数情况下,并发粒度达不到设置的粒度,竞争概率较小,反而导致更新的长时间等待(因为锁定一段后整个段就无法更新了)三是提高GC效率。

1.2 继承关系:

HashTable 是基于陈旧的 Dictionary 类继承来的。

HashMap 继承的抽象类 AbstractMap 实现了 Map 接口。

ConcurrentHashMap 同样继承了抽象类 AbstractMap,并且实现了 ConcurrentMap 接口。

1.3 允不允许null值:

HashTable 中,key 和 value 都不允许出现 null 值,否则会抛出 NullPointerException 异常。

HashMap 中,null 可以作为 key、value 都可以。

ConcurrentHashMap 中,key、value 都不允许为 null。

2. HashMap 的数据结构

2.1 什么是hash表?

哈希表(Hash Table)是一种常见的数据结构,也被称为散列表。它通过使用哈希函数将键映射到存储桶中,以实现高效的键值对存储和查找操作。

哈希表的基本原理是,通过将键(key)作为输入,经过哈希函数的计算,得到一个对应的哈希码(hash code)。这个哈希码通常是一个整数,用于确定键在哈希表中的存储位置。

哈希表内部由一个数组(数组的每个元素称为桶)和哈希函数组成。当需要存储一个键值对时,哈希函数计算出键的哈希码,并将其映射到对应的桶中。如果多个键具有相同的哈希码,即发生哈希冲突,常见的解决方法是使用链表或开放地址法来处理冲突。

在哈希表中,通过键的哈希码可以快速定位到对应的桶,从而实现快速的查找和插入操作。哈希表的平均时间复杂度为 O(1),即常数时间,但在最坏情况下,哈希冲突较多时,时间复杂度可能会退化为 O(n),其中n是存储的键值对数量。

哈希表在实际应用中被广泛使用,例如在编程语言中的字典(Dictionary)或映射(Map)数据结构中,用于高效地存储和查找键值对。

2.2 HashMap 的数据结构

在 Java 中,保存数据有两种比较简单的数据结构:数组链表

数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。

  • JDK1.8 以前 HashMap 内部数据结构使用 数组 + 链表 进行存储。(了解即可)

  • JDK1.8 以后 HashMap 内部数据结构使用 数组 + 链表 + 红黑树 进行存储。

在这里插入图片描述

3. 什么是hash冲突,怎么解决?

3.1 什么是hash冲突?

哈希表内部由一个数组(数组的每个元素称为桶)和哈希函数组成。当需要存储一个键值对时,哈希函数计算出键的哈希码,并将其映射到对应的桶中。如果多个不同键具有相同的哈希码,即发生哈希冲突

比如:对应不同的 key 可能获得相同的 hash code,即 key1 ≠ key2,但是H(key1) = H(key2)。

3.2 为什么不能完全避免hash冲突?

  1. 哈希函数是从关键字集合和地址集合的映像,通常关键字集合为无限大、长度不受限制(密码、或者文件都可以作为关键字),而地址集合却有限,无限量映射到有限量上肯定是存在重合的部分,这就是冲突。

  2. 哈希函数的复杂性:设计一个完全避免冲突的哈希函数是非常困难的。哈希函数需要具备均匀地将输入映射到输出空间的特性,但在实际情况下,很难找到一个完美的哈希函数,尤其是当输入数据的特征和分布较为复杂时。

尽管无法完全避免哈希冲突,但我们可以通过合理选择和设计哈希函数、调整哈希表的大小和负载因子等方法来降低冲突的概率。此外,使用解决冲突的方法,如链表法或开放地址法,可以处理哈希冲突并保证数据的正确性和高效性。

3.2 hash冲突怎么解决?

(1)开放定址法(再散列法)

开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。

(2)再哈希法

当哈希地址发生冲突用其他的函数计算另一个哈希函数地址,直到冲突不再产生为止。

(3)建立公共溢出区

将哈希表分为基本表和溢出表两部分,发生冲突的元素都放入溢出表中。

(4)链地址法

HashMap 把冲突的这些 key 组成一个单向链表,然后采用尾插法,把这样一个 key 保存到链表的尾部,另外为了避免链表过长影响查询效率,在链表长度大于 8,并且数组长度大于等于 64 的时候,HashMap 会把当前链表转化为红黑树,从而减少链表查询时间复杂度的问题,来提升查询效率。

4. 为什么在 JDK8 中 HashMap 要转成红黑树?

4.1 为什么不继续使用链表?

HashMap 解决hash冲突是通过链地址法完成的,在 JDK8 之前,如果产生冲突,就会把新增的元素增加到当前桶所在的链表中。

这样就会产生一个问题,当某个 bucket 冲突过多的时候,其指向的链表就会变得很长,这样如果 put 或者 get 该 bucket 上的元素时,复杂度就无限接近于O(N),这样显然是不可以接受的。

所以在 JDK1.7 的时候,在元素 put 之前做 hash 的时候,就会充分利用扰动函数,将不同 key 的 hash 尽可能的分散开。不过这样做起来效果还不是太好,所以当链表过长的时候,我们就要对其数据结构进行修改。

4.2 为什么是红黑树?

(1)二叉树

所谓的二叉查找树,一定是 left < root < right,这样我们遍历的时间复杂度就会由链表的 O(N) 变为二叉查找树的 O(logN),二叉查找树如下所示:

在这里插入图片描述

二叉搜索树通过增加了一条搜索路径,提高了查询效率,查找的效率取决于树的深度(高度)。但是,对于极端情况,当子节点都比父节点大或者小的时候,二叉查找树又会退化成链表,查询复杂度会重新变为 O(N),如下所示:

在这里插入图片描述

(2)二叉平衡树

二叉平衡树会在每次插入操作时来检查每个节点的左子树和右子树的高度差至多等于1,如果 >1,就需要进行左旋或者右旋操作,使其查询复杂度一直维持在 O(logN)。

但是这样就万无一失了吗?其实并不然,我们不仅要保证查询的时间复杂度,还需要保证插入的时间复杂度足够低,因为平衡二叉树要求高度差最多为 1,非常严格,导致每次插入都需要左旋或者右旋,极大的消耗了插入的时间。

在这里插入图片描述
对于那些插入和删除比较频繁的场景,AVL树显然是不合适的。为了保证查询和插入的时间复杂度维持在一个均衡的水平上,所以就引入了红黑树

(3)红黑树(自平衡二叉查找树)

在红黑树中,所有的叶子节点都是黑色的的空节点,也就是叶子节点不存数据;任何相邻的节点都不能同时为红色,红色节点是被黑色节点隔开的,每个节点,从该节点到达其可达的叶子节点的所有路径,都包含相同数目的黑色节点。

我们可以得到如下结论:红黑树不会像 AVL树 一样追求绝对的平衡,它的插入最多两次旋转,删除最多三次旋转,在频繁的插入和删除场景中,红黑树的时间复杂度,是优于AVL树的。

在这里插入图片描述

综上所述,这就是HashMap选择红黑树的原因。

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

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

相关文章

输入文本波形动画

效果展示 CSS 知识点 绝对定位 实现页面基础布局 <div class"input_box"><input type"text" required /><!-- 动画实际执行者 --><label>Wavy Input Text Aimation</label> </div>使用 JS 把 label 标签的文字拆分…

UG\NX二次开发 特征选择对话框 UF_UI_select_feature

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 感谢粉丝订阅 感谢 qq_42007619 订阅本专栏,非常感谢。 简介: UG\NX二次开发 特征选择对话框 UF_UI_select_feature 效果: 代码: #include <vector>…

[硬件基础]-快速了解触发器

快速了解触发器 文章目录 快速了解触发器1、触发器概述2、触发器和锁存电路之间的区别3、触发器的类型3.1 SR触发器3.2 D触发器3.3 JK触发器3.4 SR触发器和JK触发器的区别3.5 T触发器 触发器是制造存储器件和数字逻辑电路的最重要主题之一。 在本文中&#xff0c;我将讨论触发器…

在LangChain中使用Milvus + openai使用

Milvus(opens in a new tab) 是一个存储、索引和管理由深度神经网络和其他机器学习&#xff08;ML)模型生成的大规模嵌入向量的数据库。 1.文档分割 from langchain.document_loaders import PyPDFLoader pdfloader PyPDFLoader("D:\py\LangChaindao\操作系统原理.pdf&…

安全性算法

目录 一、安全性算法 二、基础术语 三、对称加密与非对称加密 四、数字签名 五、 哈希算法 六、哈希算法碰撞与溢出处理 一、安全性算法 安全性算法的必要性&#xff1a; 安全性算法的必要性是因为在现代数字化社会中&#xff0c;我们经常需要传输、存储和处理敏感的数据…

Linuxzhi6通过源代码编译安装软件

目录 一、使用源代码安装软件的优点 二、编译需求 三、安装 一、使用源代码安装软件的优点 由于自由软件的最新版本大都以源码的形式最先发布&#xff0c;编译安装可以获得软件的最新版本&#xff0c;及时修 复bug 如果当前安装的程序无法满足需求&#xff0c;用户可以根据…

合宙Air780e+luatos+腾讯云物联网平台完成设备通信与控制(属性上报+4G远程点灯)

1.腾讯云物联网平台 首先需要在腾讯云物联网平台创建产品、创建设备、定义设备属性和行为&#xff0c;例如&#xff1a; &#xff08;1&#xff09;创建产品 &#xff08;2&#xff09;定义设备属性和行为 &#xff08;3&#xff09;创建设备 &#xff08;4&#xff09;准备参…

Python小技巧:快速合并字典dict()

文章目录 前言知识点字典合并1. dict.update()基础合并2. 字典推导式 update() 后话 前言 这里是Python小技巧的系列文章。这是第四篇&#xff0c;快速合并字典。 在Python的使用中&#xff0c;有时候需要将两个 dict(字典) 进行合并。 通常我们会借助 dict(字典) 的内置方法 …

【C语言】编译和链接

前言&#xff1a; 编译和链接是计算机程序开发中的两个重要步骤&#xff0c;用于将源代码转化为可执行的程序。 文章目录 一、翻译环境和运行环境二、翻译环境中的编译2.1 预处理&#xff08;预编译&#xff09;2.2 编译2.2.1 语法分析2.2.2 语法分析2.2.3 语义分析 2.3 汇编 三…

【Audio】正弦波生成原理及C++代码

正弦波生成及频谱分析 正弦波公式 诊断系统&#xff08;Diag&#xff09;会通过播放一段指定频率、采样率、时长及振幅的正弦音&#xff0c;以此对Audio测试。正弦波的公式如下&#xff0c;其中 A是振幅、x是时间、F是频率。 y A ∗ sin ⁡ ( 2 ∗ π ∗ x ∗ F ) y A* \s…

【考研数学】高等数学第七模块 —— 曲线积分与曲面积分 | 4. 对坐标的曲面积分(第二类曲面积分)与场论初步

文章目录 二、曲面积分2.2 对坐标的曲面积分&#xff08;第二类曲面积分&#xff09;1. 问题产生 —— 流量2. 对坐标的曲面积分的定义&#xff08;了解&#xff09;3. 对坐标的曲面积分的性质4. 对坐标的曲面积分的计算法&#xff08;1&#xff09; 二重积分法&#xff08;2&a…

properties文件和yaml文件的区别~

之前&#xff0c;关于数据库的连接信息&#xff0c;端口号的设置等&#xff0c;我们会将它分门别类的写在多个文件中&#xff0c;但SpringBoot&#xff0c;它讲究统一的配置管理&#xff0c;我们想设置的任何参数都集中在一个固定位置和命名的配置文件&#xff0c;而该配置文件…

10.4| QT实现TCP服务器客户端搭建的代码,现象

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>#include<QTcpServer> //服务器头文件 #include<QTcpSocket> //客户端头文件#include<QList> //链表容器 #include<QMessageBox> …

Error string: Could not load library

启动Rivz时&#xff0c;报错&#xff1a; Error string: Could not load library (Poco exception libg2o_csparse_extension.so.0.1: cannot open shared object file: No such file or directory) [ERROR] [1696572310.529059051]: Failed to load nodelet [/radar_graph_s…

破译滑块验证间距 破译sf顺丰滑块验证

废话不多说直接开干&#xff01; from selenium import webdriver # 导入配置 from selenium.webdriver.chrome.options import Options import time from PIL import Image # 导入动作链 from selenium.webdriver.common.action_chains import ActionChains import random, st…

如何获取高质量的微信私域客户?

在当今数字化时代&#xff0c;企业都在努力寻求创新的营销方式来获取更多的客户。微信私域流量作为一种精准的营销工具&#xff0c;越来越受到企业的青睐。那么&#xff0c;如何获取高质量的微信私域客户呢&#xff1f;本文将为你揭示这一难题的答案&#xff0c;让你轻松Get高转…

STM32--MQ2烟雾传感器

本文主要介绍STM32F103C8T6和烟雾传感器模块的控制算法 简介 烟雾模块选用MQ-2气体传感器&#xff0c;根据传感器的电导率随空气中可燃气体浓度的增加而增大的特性检测空气中可燃气体&#xff0c;然后将电导率的变化转换成对应的电信号 MQ系列烟雾传感分类如下&#xff1a; 该…

基于SSM的校园二手物品交易平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Python之字符串构造

Python之字符串构造 字符串str 一个个字符组成的有序的序列&#xff0c;是字符的集合使用单引号、双引号、三引号引住的字符序列字符串是不可变对象&#xff0c;是字面常量 Python3起&#xff0c;字符串都是Unicode类型 x abcde使用for循环遍历x的值&#xff0c;打印并查看…

九小场所消防安全检查安全码系统

九小场所安全码&#xff0c;实现消防安全监督管理&#xff0c;落实消防安全责任&#xff0c;形成九小场所网格化监控、动态化管理&#xff1b; 安全码流程化管理 监管部门日常检查&#xff0c;微信扫码即可填写检查记录&#xff0c;现场可拍照、视频、文字、记录检查情况&…