java 集合框架-map(键值对集合)

news2024/9/20 18:30:19

一、Map接口 (键值对集合)

1.实现类

(1).线程不安全

HashMap

1.特点:

        ①无序 

         ②查找效率高:根据key,查找value

2.数据结构:数组(哈希表)+ 链表(链地址法解决哈希表冲突) + 红黑树(自平衡二叉树,提高查找效率)          

①数组(哈希表):
HashMap内部定义了一个数组,数组中的每个位置被称为“桶”( Bucket ),这是HashMap的基础结构【哈希表】
        下标位置:当添加一个新的key-value键值对时,会根据key的 hashcode(),通过哈希函数计算出一个新的哈希值 h
ash,并通过这个hash值,计算key-value键值对在数组中的下标位置(桶Bucket ) ;
        数组容量:在添加第一个key-value键值对时,数组容量被初始化为 16,并且可以根据key-value 键值对的数量和负载因子,数组会自动按照2倍进行扩容;
②链表:
        数组的每个位置( Bucket桶)可以保存一个或多个key-value键值对;
        当两个或更多的 key-value键值对,被映射保存到数组的同一个位置(桶Bucket)时,就产生了哈希表冲突;
        HashMap使用链地址法,解决哈希冲突,这些键值对将以链表的形式存储在产生冲突的位置(桶Bucket ) ;
③红黑树:
        为了优化链表的查询性能,当链表长度超过一个阈值(默认是8)并且数组的容量大于等于64时,链表会转换成红黑树;
        红黑树是一种自平衡的二叉查找树,它可以基于二分查找的方式,进行元素的查找,提高查找搜索性能,这对于较长的链表来说是一个明显的性能提升;
        当红黑树中的节点数量减少到6个或更少时,红黑树将转换回链表;

源码分析:

3.关键计算:计算key-value键值对在哈希表中的存储位置(桶)     

哈希运算,计算新的哈希值,hash( )扰动函数 (h = key.hashCode()) ^ (h >>> 16)

目的:计算新的哈希值,降低哈希冲突概率
通过新哈希值,计算下标位置(桶位置) ,(n - 1) & hash  

4.转换成红黑树的条件:链表的元素个数超过8,并且数组长度大于等于64

5.转换成红黑树的优点:

  • 链表过长,会导致搜索效率降低,使用红黑树提高查找效率;
  • 红黑树,是一颗自平衡的二叉查找树,树中所有节点均自动排序,并且自平衡,可以使用二分查找,提高查找效率。 

6.影响性能的关键参数:

  ①数组容量:默认为16

  • 容量越大,内存占用越多,产生冲突的概率越小
  • 必须为2的N次幂
  • 每次按照2倍进行扩容,最大容量不超过2的30次幂

    ②加载因子:默认为0.75

  • 加载因子越高,代表利用率越高,产生冲突的概率越高
  • 加载因子越低,代表利用率越低,产生冲突的概率越低 

5.扩容条件:

  • 默认情况下,数组长度为16(自定义时,必须保证数组长度为2^n 次幂)
  • 默认情况下,数组长度为16(自定义时,必须保证数组长度为2^n 次幂)
  • 达到扩容阈值threshold,按照2倍进行扩容
  • 链表长度大于8,数组长度小于64,链表不会转换成红黑树,执行数组扩容
LinkedHashMap 

1.特点:有序

2.数据结构:HashMap的子类,多维护了一条双向链表,保存顺序

TreeMap 

1.特点:自动按照key排序

2.数据结构:红黑树 

(2).线程安全 

Hashtable

1.特点:无序、key和value不允许为null

2.数据结构:数组+链表

3. 线程安全:通过“synchronized”同步锁实现

ConcurrentHashMap

1.特点:无序

2.数据结构:数组+链表+红黑树 

3.线程安全:synchronized同步锁 + CAS无锁化编程模型

二、Collections工具类

        封装了集合的常见算法和操作 

三、常见的面试题

1.HashMap . LinkedHashMap .TreeMap的区别?

HashMap :无序,基于数组+链表+红黑树实现;
LinkedHashMap:有序,HashMap的子类;
TreeMap :自动排序,按照key或者自定义Comparator比较器,进行排序;

2.HashMap和 Hashtable的区别?
 

HashMap和 Hashtable都是Map接口的键值对集合实现类,它们的区别主要包括:

  •  线程安全: HashMap是非线程安全的,而 HashTable线程安全;
  •  执行效率:由于 HashTable使用synchronized同步锁实现线程安全所,以 HashTable效率要比HashMap略低;
  • 使用Nu11做key和value :

HashMap:可以使用null 作为key 和value;

  • HashTable:不允许有null键和null值,否则会抛出NullPointerException异常;
  • 数据结构:HashMap:数组+链表+红黑树;HashTable:数组+链表;
  • 扩容方式:

        HashMap : 默认的初始化大小为16。之后每次扩充,容量变为原来的 2倍;
        HashTable:默认的初始大小为11,之后每次扩充,容量变为原来的 2n+1 ;

3.HashMap的数据结构是什么?

①数组(哈希表):
HashMap内部定义了一个数组,数组中的每个位置被称为“桶”( Bucket ),这是HashMap的基础结构【哈希表】
        下标位置:当添加一个新的key-value键值对时,会根据key的 hashcode(),通过哈希函数计算出一个新的哈希值 h
ash,并通过这个hash值,计算key-value键值对在数组中的下标位置(桶Bucket ) ;
        数组容量:在添加第一个key-value键值对时,数组容量被初始化为 16,并且可以根据key-value 键值对的数量和负载因子,数组会自动按照2倍进行扩容;
②链表:
        数组的每个位置( Bucket桶)可以保存一个或多个key-value键值对;
        当两个或更多的 key-value键值对,被映射保存到数组的同一个位置(桶Bucket)时,就产生了哈希表冲突;
        HashMap使用链地址法,解决哈希冲突,这些键值对将以链表的形式存储在产生冲突的位置(桶Bucket ) ;
③红黑树:
        为了优化链表的查询性能,当链表长度超过一个阈值(默认是8)并且数组的容量大于等于64时,链表会转换成红黑树;
        红黑树是一种自平衡的二叉查找树,它可以基于二分查找的方式,进行元素的查找,提高查找搜索性能,这对于较长的链表来说是一个明显的性能提升;
       当红黑树中的节点数量减少到6个或更少时,红黑树将转换回链表;

4.HashMap中put( )的执行过程?
 

①计算哈希码:
。向Hashwlap中添加一个新的 key-value键值对时,首先会调用key键的hashcode()方法来计算一个hash哈希值。(这个哈希值将被用于计算key-value键值对,在数组中保存时的下标位置)
②计算数组下标:
。计算完hash哈希值后,HashNap会通过数组长度n,按照(n-1)& hash 的方式,将哈希值转化为数组下标;。(n-1) & hash的作用等同于hash % n,位运算比算术运算的效率高;
③处理哈蒂冲突:
。如果不同key按照各自不同的hash哈希值,计算的数组下标位置相同,这种情况称为哈希表冲突;
。HashMap使用链地址法来处理哈希表冲突,在数组的每个位置存放一个链表或红黑树(当链表长度达到一定阈值时会转换为红黑树)。因此,新的键值对会被添加到当前位置的链表或红黑树中;
④检查键是否已存在:
。在将键值对放入对应位置之前,HashMap会检查该位置是否存在与新键相等的对象;
。会调用equals()方法来比较键之间的相等性。如果找到相同的键,那么旧的值将被新值替换,返回旧值;否则,新键值对将被添加;
⑤插入新节点:
。如果没有找到相等的键,新键值对将被插入到该位置的链表头部或红黑树中;
。当链表长度达到8且数组容量大于64时,链表会转化为红黑树,用来优化查找性能;
⑥检查容量和扩容:
。每次插入新键值对后,HashNap会检查当前元素数量是否超过了它的扩容阈值(容量乘以加载因子(默认为0.75 ) ) ;。如果超过了扩容阈值,HashMap会按照2倍进行扩容;
⑦返回旧值:
。如果在插入过程中发现键已经存在,put()方法会返回旧的值;。如果键不存在,插入了一个新键值对,put()方法将返回null ;

5.HashMap如何计算key-value键值对元素在数组中的存储位置?

·为了使key-value元素可以均匀散列的保存在(Hashlap的数组中,所以使用key的哈希值进行哈希扰动计算出一个新的 hash值。
·在JDK 1.8版本以前,Hashwap会将这个hash值与数组长度进行%模运算出一个下标值,从而确定key-value在数组中的存储位置;
。例如:数组长度默认为16,12580 % 16 = 4,753951 % 16 = 15。所以哈希值为12580 、 753951的键值对,会存储在数组下标为4和3的位置。
·在JDK 1.8版本以后,由于“%”模运算性能消耗比较大,所以采用(长度– 1) & hash的位运算方式来计算存储位置;
。例如:数组长度默认为16,(16 - 1) & 12580=4,(16 - 1) & 753951。所以哈希值为12580 、 753951的键值对,会继续存储在数组下标为4和3的位置。


6.什么是哈希冲突?

·哈希冲突是在使用哈希函数或哈希表时遇到的一种特殊情况;
·如果发生在哈希函数,哈希冲突是指当发生在两个不同的输入值,经过哈希函数处理后产生了相同的哈希值;
·如果发生在哈希表,哈希冲突是由于哈希表的大小是有限的,而输入的数据集合可能是无限的,因此,当不同的输入数据映射到哈希表的同一个位置时,就会出现哈希冲突;


7.如何解决哈希冲突?

处理哈希冲突的方法主要有以下几种:
1,开放寻址法(open Addressing )∶当哈希冲突发生时,使用某种探测技术在哈希表中寻找下一个空位来存储数据。
2,链地址法(chaining )∶每个哈希表的槽位都维护一个链表。当哈希冲突发生时,所有哈希值相同的元素都被存储在同一个位置
对应的链表中。这种方法也称为拉链法。
3,再哈希法(Rehashing )∶当哈希冲突发生时,使用第二个哈希函数再次计算哈希值,直到找到空槽位。这种方法会增加计算复
杂度,但可以减少哈希表的装载因子,从而提高查找效率。
4,建立一个公共溢出区︰将哈希表分为基本表和溢出表两部分。所有哈希地址不冲突的元素都存放在基本表中,所有哈希地址冲突的元
素都存放在溢出表中。

 

8.HashMap如何解决哈希冲突?

HashMap使用链地址法来处理哈希表冲突,当产生哈希冲突时,HashMap会将产生冲突的Key-value键值对,通过一个链表保存在数组产生冲突的位置中;


9.HashMap的长度为什么是2的幂次方(2的倍数)?

HashMap为什么按照2倍进行扩容?
因为必须保持HashMap的的容量为2的幂次方
。降低哈希冲突概率:
。当HashMap中的数组长度为②的幂次方,不同的key计算得到 index相同的几率较小,不容易产生冲突;
·提高计算效率:
HashMap中使用哈希表保存时,索引计算公式为i = (n - 1) & hash 。
。如果n为②的幂次方,那么n-1的低位全是1,那么使用hash哈希值进行&与操作时,可以保证低位的值不变的情况下,高位更多的参与运算,从而保证分布均匀散列;
。同时,(n - 1) & hash效果等同于 hash % n,但是&与运算属于位运算,效率比“%”模运算性能要高;

 

10.HashMap影响性能的两个参数?

·构建HashMap实例时有两个重要的参数会影响其性能:初始容量和加载因子
·初始容量:用来规定哈希表数组的容量长度,默认为16,因为16是②的幂次方的原因,所以在小数据量的情况下,能减少哈希冲突,提高性能。如果存储大容量数据的时候,最好预先判断数据量,按照②的幂次方,提前预设初始容量;
·加载因子:用来表示哈希表中元素的填满程度,默认为 0.75,越大则表示允许填满的元素就越多,哈希表的空间利用率就越高,但是冲突的机会增加。反之,越小则冲突的机会就会越少,但是空间很多就浪费。
。所以,在设置初始容量时,应该考虑到初始容量及其加载因子,预估设置初始容量,最大限度降低扩容操作频率。


11.HashMap的扩容机制?

HashMap的用来进行扩容的方法是resize()方法;HashMap在以下三种场景下,会触发扩容机制:
1.当Hashwap通过无参构造方法创建,在第一次调用put()方法添加key-value键值对时,数组初始化为16 ;

2当Hashwap 中的元素个数超过扩容阈值 threshold时,数组的容量按照原容量的②倍进行扩容:
        ·扩容阈值threshold=数组容量×加载因子LoadFactor ;
        ·加载因子LoadFactor的默认值为 0.75,数组容量默认为16,扩容阈值 threshold默认为12 ( 16 × 0.75 =12 ) ;所以,当Hashwap中元素个数超过12时,数组的容量按照原容量的②倍进行扩容(( 16 x 2 = 32 );

3.加入元素时,如果链表长度大于阈值(默认为8)并且数组长度小于64,会产生数组扩容;

13.HashMap为什么使用链表?

·Hashwap使用哈希表作为基础数据结构,当两个不同的 key-value键值对,通过 hash哈希值计算数组下标,出现相同下标情况时,产生哈希冲突;
. Hashtap使用“链地址法”解决哈希冲突,所以需要使用链表,来保存产生哈希冲突的 key-value键值对;
 

14.HashMap为什么使用红黑树?

. HashMap中的链表长度增长到一定长度,会导致搜索性能下降;(链表是线性方式搜索)
·所以,Hashap会在链表过长时,将链表转换为红黑树,通过红黑树提供搜索性能;(红黑树是二分查找方式搜索)
.Hashap不直接用红黑树的原因是:链表简单易于维护,红黑树维护复杂。所以首选使用链表,只有链表长度过长时,才会转换成红黑树来提高搜索查找的性能;


15.红黑树有哪些特点?

HashMap中的红黑树
红黑树是一种自平衡二叉查找树:
。二叉查找树:树中的所有节点满足排序规则(left < root < right ),可以基于二分查找进行搜索;
·自平衡:保持左右子树的平衡,保持搜索性能。不会出现退化成链表的极端情况(所有子节点都保存在左子树或右子树);·所以,HashMap使用红黑树来优化长链表;


16. HashMap链表转换红黑树的条件?
 

在HashNap 中,当链表转换为红黑树,需要同时满足两个条件︰链表长度大于等于8,并且数组容量大于等于64 ;
1,链表长度:当链表的长度大于等于⑧时(有8个或更多的元素在(HashNap的同一个桶( bucket) 中形成链表),这是因为
在链表长度较小的情况下,链表的线性查找效率还可以接受,但是一旦当链表长度较长时,必须通过将链表转换成红黑树这种方式,才能够提供更好的查找性能。
2,数组容量︰在链表达到阈值8时,同时还要检查 HashNap的底层数组(哈希表)的容量大于等于64。因为Hashwap不会轻
易使用红黑树,虽然红黑树的搜索性能比链表好,但是维护更复杂。只有在链表足够长,只有红黑树才能带来明显性能提升时,才会进行转换。
。所以,如果数组容量小于64,即使链表长度超过8,也不会立即进行红黑树的转换,而是先进行数组的扩容,将HashMa中的所有元素重新散列保存,用来降低链表的长度。(优先使用链表)

 

17.HashMap红黑树退化成链表的条件?
 

当红黑树中的节点数量减少到6个或更少时,红黑树将转换回链表;·因为,红黑树中的节点过少时,使用链表来保存。维护会更简单高效;·这种机制,可以让HashMap在性能和资源使用之间找到一个平衡点;
 

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

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

相关文章

UDP的报文结构及其注意事项

1. 概述 UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接的传输层协议&#xff0c;它提供了一种简单的数据传输服务&#xff0c;不保证数据的可靠传输。在网络通信中&#xff0c;UDP通常用于一些对实时性要求较高、数据量较小、传输延迟较低的应用&#xff0c…

大数据的数据质量有效提升的研究

大数据的数据质量有效提升是一个涉及多个环节和维度的复杂过程。以下是从数据采集、处理、管理到应用等方面&#xff0c;对大数据数据质量有效提升的研究概述&#xff1a; 一、数据采集阶段 明确采集需求&#xff1a;在数据采集前&#xff0c;需明确数据需求&#xff0c;包括…

Mike21粒子追踪模型particle tracking如何展示粒子轨迹

前言&#xff1a; 随着模型的推广&#xff0c;模型的很多模块也问的多了起来&#xff0c;PT粒子追踪模块最近群友也在问&#xff0c;结果算了出来&#xff0c;却实现不了展示运动轨迹。今天就写段简单的PT后处理的方法吧。 注意&#xff1a;MIKE21输出模块中不但输出了关于水…

3个管人绝招,让下属心服口服

管人不能瞎管&#xff0c;手段很重要&#xff1a;3个管人绝招&#xff0c;让下属心服口服 一&#xff1a;差异化管理&#xff0c;玩弄人性 谁赞成&#xff0c;谁反对&#xff0c;看清楚谁顺从自己&#xff0c;谁反对自己之后&#xff0c;接下来要做的便是区别对待。 给听话的…

简单的CSS样式

样式分为三种 内部样式&#xff1a;写在html文件里的样式叫内部样式 内联样式&#xff1a;写在需要的标签中 外部样式&#xff1a;写在外部css文件里 可以通过不同的选择器来选择设置指定组件的样式&#xff1a; <style>/* 写在html文件里的样式叫内部样式 *//* 选择器 *…

PEFT LoRA 介绍(LoRA微调使用的参数及方法)

一 PEFT LoRA 介绍 官网简介如下图&#xff1a; 翻译过来是&#xff1a;低秩自适应(LoRA)是一种PEFT方法&#xff0c;它将一个大矩阵在注意层分解成两个较小的低秩矩阵。这大大减少了需要微调的参数数量。 说的只是针对注意力层&#xff0c;其实我自己平时微调操作注意力层多…

一款功能强大的视频编辑软件会声会影2023

会声会影2023是一款功能强大的视频编辑软件&#xff0c;由加拿大Corel公司制作&#xff0c;正版英文名称为‌Corel VideoStudio。它具备图像抓取和编修功能&#xff0c;可以处理和转换多种视频格式&#xff0c;如‌MV、‌DV、‌V8、‌TV和实时记录抓取画面文件。会声会影提供了…

微服务上(黑马)

文章目录 微服务011 认识微服务1.1 单体架构1.2 微服务1.3 SpringCloud 2 微服务拆分2.1 熟悉黑马商城2.2 服务拆分原则2.2.1.什么时候拆2.2.2.怎么拆 2.3 拆分服务2.3.1 拆分商品管理功能模块2.3.2 拆分购物车功能模块 2.4 远程调用2.4.1 RestTemplate2.4.2.远程调用 2.5 总结…

SpringBoot-21 SpringBoot微服务的发布与部署(3种方式)

基于 SpringBoot 的微服务开发完成之后&#xff0c;现在到了把它们发布并部署到相应的环境去运行的时候了。 SpringBoot 框架只提供了一套基于可执行 jar 包&#xff08;executable jar&#xff09;格式的标准发布形式&#xff0c;但并没有对部署做过多的界定&#xff0c;而且为…

25届最近5年广东工业大学自动化考研院校分析

广东工业大学 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、初试大纲复试大纲 七、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指定教材 1、考试科目介绍 2、指定教…

【在排序数组中查找元素的第一个和最后一个位置】python刷题记录

R2-分治 有点easy的感觉&#xff0c;感觉能用哈希表 class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:nlen(nums)dictdefaultdict(list)#初始赋值哈希表&#xff0c;记录出现次数for num in nums:if not dict[num]:dict[num]1else:dict[…

(深层与双向)循环神经网络

一、深层循环神经网络 1、对于循环神经网络 2、对于深层&#xff0c;要得到更多的非线性&#xff0c;就像多层感知机&#xff08;MLP&#xff09;。 &#xff08;1&#xff09;浅层与深层对比 这是具有&#x1d43f;个隐藏层的深度循环神经网络&#xff0c; 每个隐状态都连续…

【QT】QT 系统相关(事件、文件、多线程、网络、音视频)

一、Qt 事件 1、事件介绍 事件是应用程序内部或者外部产生的事情或者动作的统称。在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口需要重新绘制…

《python程序语言设计》第6章14题 估算派值 类似莱布尼茨函数。但是我看不明白

这个题提供的公式我没看明白&#xff0c;后来在网上找到了莱布尼茨函数 c 0 for i in range(1, 902, 100):a (-1) ** (i 1)b 2 * i - 1c a / bprint(i, round(4 / c, 3))结果 #按题里的信息&#xff0c;但是结果不对&#xff0c;莱布尼茨函数到底怎么算呀。

【计算机网络】TCP协议详解

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 1、引言2、udp和tcp协议的异同3、tcp服务器3.1、接口认识3.2、服务器设计 4、tcp客户端4.1、客户端设计4.2、说明 5、再研Tcp服务端5.1、多进程版5.2、多线程版 5、守护进程化5.1、什么是守护进程5.2…

Javascript面试基础6(下)

获取页面所有checkbox 怎样添加、移除、移动、复制、创建和查找节点 在JavaScript中&#xff0c;操作DOM&#xff08;文档对象模型&#xff09;是常见的任务&#xff0c;包括添加、移除、移动、复制、创建和查找节点。以下是一些基本的示例&#xff0c;说明如何执行这些操作&a…

【网络世界】HTTP协议

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 概念 &#x1f4c1; URL &#x1f4c2; urlencode 和 urldecode &#x1f4c1; 协议格式 &#x1f4c1; 方法 &#x1f4c2; GET/get &#x1f4c2; POST/post &#x1f4c1; 常见的报头 &#x1f4c1; 状态码 &…

Web3 职场新手指南:从技能到素养,求职者如何脱颖而出?

随着 2024 年步入下半年&#xff0c;Web3 行业正在经历一系列技术革新。通过改进的跨链交互机制和兼容性&#xff0c;逐步消除市场碎片化的问题。技术的进步为开发者和用户都打开了新的前景。然而&#xff0c;复杂的技术和快速变化的市场环境也让许多新人望而却步。求职者如何找…

编译固件 -- 自用

编译环境 先安装编译环境 git clone <编译仓库路径> git checkout <编译主分支> 更新/下载 然后就是一样的更新下载 ./scripts/feeds update -a ./scripts/feeds install -a 然后直接编译 feeds/puppies/rom/scripts/make.sh 对应型号 make Vs 这里的对应型号可…

gitee的fork

通过fork操作&#xff0c;可以复制小组队长的库。通过复制出一模一样的库&#xff0c;先在自己的库修改&#xff0c;最后提交给队长&#xff0c;队长审核通过就可以把你做的那一份也添加入库 在这fork复制一份到你自己的仓库&#xff0c;一般和这个项目同名 现在你有了自己的库…