【常见集合】Java 常见集合重点解析

news2024/11/17 6:26:19

Java 常见集合重点解析

1. 什么是算法时间复杂度?

在这里插入图片描述

  • 时间复杂度表示了算法的 执行时间数据规模 之间的增长关系;

什么是算法的空间复杂度?

  • 表示了算法占用的额外 存储空间数据规模 之间的增长关系;

常见的复杂度:

在这里插入图片描述

2. ArrayList 底层的数据结构是什么?

推荐博客

ArrayList 的底层是动态数组(Array),是一种用 连续的内存空间 存储 相同数据类型 数据的现象数据结构(单列),并且会随着数据的增加而扩容;

数组下标为什么从 0 开始?

  • 数组通过下标访问的原理就是通过数组的首元素地址与下标去计算对应下标元素的地址,从而访问对应的元素;
  • 寻址公式:baseAddress + i * dataTypeSize,计算下标的内存地址效率较高;
  • 如果是从 1 开始:寻址公式则为 baseAddress + (i - 1) * dataTypeSize,这样计算下标的时候还多了一步减法;
    • 而这个高频的操作,“日积月累”,如 几亿次的操作,这个减法也挺消耗 CPU 资源的,要尽可能的提高效率;

查找的时间复杂度?

  • 随机查询(通过下标)的时间复杂度是 O(1);
  • 查找元素(未知下标的值查询)的时间复杂度是 O(n);
  • 查找元素(未知下标但是已排序)通过二分的时间复杂度是 O(logn);

插入、修改、删除的时间复杂度?

  • 修改的时候,通过下标访问并修改即可,所以是O(1);
  • 按下标插入和删除的时候,为了保证数组的内存连续性,需要挪动数组元素,平均时间复杂度是 O(n);
    • 插入的时候甚至可能会扩容:O(n);

3. ArrayList 源码(底层原理)有了解过吗?

构造方法:

在这里插入图片描述

扩容机制:

  1. 空集合但是容量为0,即空数组;
    • 第一次添加元素的时候,如果 需要的空间大小 minCapacity 小于默认容量,则扩容至默认容量;
  2. 空集合但是容量不为0,即数组元素都为空;
    • 第一次添加元素的时候,与默认容量无关,按正常的情况走;
  • 添加之前要判断本此次添加 需要的空间大小 minCapacity 是否小于当前的容量,是则无需扩容,否则需要扩容;

    • 原数组扩容为原来的 1.5 倍(如果还是达不到 minCapacity,则取 minCapacity);

    • 如果扩容后的空间大于最大的数组大小,则调用一个方法计算

      在这里插入图片描述

      private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
      

      根据 minCapacity 计算出一个合理的巨大容量;

    • 然后 elementData[size++] = e,在有效数组尾添加节点;

在这里插入图片描述

ArrayList list = new ArrayList(10) 中 ArrayList 扩容了几次?

  • 0 次,调用构造方法,只是实例了一个指定容量的 ArrayList,未扩容;

4. 如何实现数组和 List 之间的转化?

在这里插入图片描述

  1. 数组 => List

使用 JDK 中 Arrays 数组工具类的 asList 方法(可变参数),将其转化为 List;

在这里插入图片描述

不难看出,如果修改原数组指向的元素,是会影响 List 的,当然,触发了扩容之后 List 就换了个数组,就不受影响;

如果要不受影响的话,就用遍历或者 stream 流去转化 List;

  1. List => 数组

使用 List 对象的 toArray 方法转化为数组:

  • 无参的返回的是 Object 数组;

在这里插入图片描述

  • 有参的则是指定类型的数组,并且如果数组足够大,数据会拷贝到数组里,反正以返回值为主就行了;

在这里插入图片描述

不难看出,每次转化数组都是拷贝一份 List 中的数据,所以修改 List 中的数据不会影响转化后的数组;

5. 链表操作数据的时间复杂度是多少?

推荐博客

单向链表只有一个方向(只有头节点),每个节点有一个后继节点 next;

在这里插入图片描述

  • 头插法,O(1)
  • 指定节点的后面插入,O(1)
  • 指定节点的前面插入,O(n)
  • 指定节点的删除,O(n)
  • 指定下标的增删查改,O(n)
  • 查找指定值,O(n)

双向链表则有两个方向(有头节点和尾节点),每个节点有一个后继节点 next 还有一个 前驱节点 prev;

  • 支持双向遍历,提高灵活性;

在这里插入图片描述

  • 头插法、尾插法,O(1)
  • 指定节点的前面/后面插入,指定节点的删除,O(1)
  • 指定下标的增删查改,O(n)
  • 查找指定值,O(n)

在这里插入图片描述

6. ArrayList 和 LinkedList 的区别是什么?

6.1 底层数据结构

ArrayList 是动态数组,LinkedList 是双写链表;

6.2 操作数据效率

  1. 下标访问

ArrayList 按照下标查询的时间复杂度是 O(1),LinkedList 则不支持下标查询,如果从逻辑上的下标查询的话,则时间复杂度是 O(n);

  1. 值查询

ArrayList 和 LinkedList 都是 O(n);

  1. 新增/删除

ArrayList 从尾部插入/删除是 O(1),但是其他部分增删需要挪动数组,甚至触发扩容,时间复杂度是 O(n);

  • 只有给定下标的 O(n);

LinkedList 从头尾节点插入都是 O(1),其他都需要遍历链表,没有扩容的情况,时间复杂度为 O(n);

  • 给定下标是需要遍历的 O(n),但是给定节点则不需要遍历的 O(1);

6.3 内存空间占用

ArrayList 底层是数组,内存连续,节省空间;

LinkedList 底层是双向链表,除了 value 还存了两个指针,更占用内存;

6.4 线程安全

ArrayList 和 LinkedList 都不是线程安全的;

要保证线程安全两种方案:

  1. 在方法内使用,局部变量是线程安全的(让多线程不同时修改同一个对象);

  2. 套壳加锁返回线程安全的 List 实例;

    在这里插入图片描述

7. 什么是二叉树?什么是二叉搜索树?什么是红黑树?

二叉树

  • 二叉搜索树(Binary Search Tree,BST),又叫二叉查找树,有序二叉树;

  • 在树中的任意一个节点,其左子树中的每个节点都小于这个节点,右子树则都大于;

  • 没有键相等的节点;

  • 通常情况下二叉搜索树的增删查改,时间复杂度是 O(logn);

    恶劣情况的二叉搜索树会退化成链表(时间复杂度退化为 O(n)):

    在这里插入图片描述

而我们需要的是平衡度高的二叉搜索树,才能保证查找效率,AVL树和红黑树都是自平衡二叉搜索树。

AVL树通过旋转操作来保持平衡,并且在平衡性上有更严格的要求。

红黑树则使用颜色标记和旋转操作来维护平衡(维持一些规则),相对而言更灵活一些。

在AVL树中,任意节点的左右子树的高度差不超过1,而红黑树的规则则是:

在这里插入图片描述

  • 红黑树(Red Black Tree):也是一种自平衡的二叉搜索树;
  • 所有的红黑规则都是希望红黑树能够保证平;
  • 红黑树的时间复杂度:增删查改都是 O(logn);
    • 旋转调整是 O(1);

8. 什么是散列表(哈希表)?

推荐博客

什么是散列表?

  • 散列表(Hash Table)又名哈希表 / Hash 表;
  • 根据键直接访问内存存储位置的数据结构;
  • 由数组演化而来,利用了数组支持按照下标进行随机访问数据的性质;
  • 数组的每个位置不一定都有值,存储的比较松散,一般会保留一定的空位置;

在这里插入图片描述

散列冲突是什么?

  • 散列冲突又叫哈希冲突、哈希碰撞;
  • 指的是多个 key 映射到同一个数组的下标位置;

散列冲突其实无法完全避免,即使是 md5 这样的算法,也无法绝对的让 key 和 hashValue 一对一,更何况我们没有那么大的数组来存;

  • 要预防或者减少哈希冲突,可以用一些均匀化的算法,让哈希冲突不要集中在某个下标,适当扩充数组…

散列冲突,如何数组同个下标的存储数据?

  • 开散列的方式:
    • 数组的每个下标称之为一个哈希桶(bucket)或者哈希槽(slot);
    • 每个哈希桶会对应一个链表/一颗红黑树;
    • 散列冲突后的元素都放到对应哈希桶内的链表/红黑树中;

9. 说一下 HashMap 的实现原理?

  • 底层使用 Hash 表数据结构,即数组 + 链表/红黑树;
  • 添加数据时,计算 key 的值确定元素在数组中的下标;
    • key 相同则替换;
    • 不同则存入链表或红黑树;
  • 获取数据通过 key 的 hash 计算下标,查询链表/红黑树下标元素,一般是可以看成是 O(1) 的;

HashMap 的 jdk1.7 和 jdk1.8 的区别:

  • jdk1.8 之前,数组 + 链表(头插);
  • jdk 1.8 及之后,数组 + 链表(尾插) + 红黑树,链表长度和数组长度各达到一定值(链表长于 8 并且数组长于 64)则会从链表转化尾红黑树;

10. HashMap 的 put 方法的具体流程?

在这里插入图片描述

哈希表被无参实例化的时候,数组没有被实例化,第一次 put 的时候,再 resize 为 16;
(因为可以由其他构造方法去构造 HashMap,所以第一次 put 时数组不为 null,可能数组长度不会以 16 开始,但是数组的长度一定是 2 的倍数)

在这里插入图片描述

  1. 判断键值对数组 table 是否为空或为 null,否则执行 resize() 进行扩容(初始化)

  2. 根据键值 key 计算 hash 值得到数组索引

  3. 判断 table[i] == null,条件成立,直接新建节点添加

  4. 如果 table[i] == null,不成立

    4.1 判断 table[i] 的首个元素是否和 key 一样,如果相同直接覆盖 value

    4.2 判断 table[i] 是否为 treeNode,即 table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对

    4.3 遍历 table[i],链表的尾部插入数据,然后判断链表长度是否大于 8,大于 8 的话把链表转换为红黑树,在红黑树中执行插入操 作,遍历过程中若发现 key 已经存在直接覆盖 value

  5. 插入成功后,判断实际存在的键值对数量 size 是否超多了最大容量 threshold(数组长度* 0.75),如果超过,进行扩容。

11. HashMap 的扩容机制?

在这里插入图片描述

参考回答:

  • 在添加元素或初始化的时候需要调用 resize 方法进行扩容,第一次添加数据初始化数组长度为 16,以后每次每次扩容都是达到了扩容阈值(数组长度 * 0.75)

  • 每次扩容的时候,都是扩容之前容量的 2 倍;

  • 扩容之后,会新创建一个数组,需要把老数组中的数据挪动到新的数组中

    • 没有hash冲突的节点,则直接使用 e.hash & (newCap - 1) 计算新数组的索引位置
    • 如果是红黑树,走红黑树的添加
    • 如果是链表,则需要遍历链表,可能需要拆分链表,判断 (e.hash & oldCap) 是否为0,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上

在这里插入图片描述

12 HashMap 的寻址方式?

在这里插入图片描述

(h = key.hashCode()) ^ (h >>> 16) ,称为 二次哈希

  1. 首先获取 key 的 hashCode 值;
  2. 然后右移 16 位异或运算原来的 hashCode 值
  • 主要作用就是使原来的 hash 值更加均匀,减少 hash 冲突,例如 17 或者 33 模 16 都等于 1,二次哈希后再取模大概率就不哈希冲突了;

(n - 1) & hash,代替取模,性能更好一些,n 即数组长度,必须是 2 的整数倍才等价于取模;

  • 例如 16 => 15 的二进制 1111,按位与就是保留后面四个比特位,就是取模;

为何 HashMap 的数组长度一定是 2 的整数倍?

  1. 计算索引时效率更高:(n - 1) & hash,代替取模,n 即数组长度,必须是 2 的整数倍才等价于取模;
  2. 扩容时重新计算索引效率更高:hash & oldCap == 0 的元素留在原地,否则 newPos = oldPos + oldCap
    • 例如 16 => 32:
    • 两次计算索引的结果一样 <=> hash 的后 4 位 和 后 5 位 相等 <=> 那么就是从右到左第 5 位必须是 0
      • 也就是 10000(即原数组长度) 按位与 hash,得知其是否为 0;
    • 所以,hash & oldCap == 0,并且在**数组为 2 的整数倍的情况下**是可以推理出来两次计算索引的结果一样(充要条件);

13. HashMap 在 jdk1.7 下,多线程死循环问题

单线程情况下:

在这里插入图片描述

多线程的情况下(两个线程同时让一个 HashMap 扩容):

在这里插入图片描述

线程 1 完成扩容:

在这里插入图片描述

线程 2 执行:

  • 现在 cur2 指向 3,会将 3 头插到扩容数组中,由于这里节点 3 跟线程 1 扩容后的节点 3 是同一个,所以就会出现这种情况:

在这里插入图片描述

  • 所以这样就会导致成环不断循环下去!

问题原因:

  1. 头插法,导致插入的顺序和原来链表的顺序相反的;
  2. table 是共享的,table 里面的元素也是共享的,while 循环都直接修改 table 里面的元素的 next 指向,导致指向混乱;

而 jdk 8 扩容算法做出了调整,使用了尾插法还有红黑树;还可以用线程安全的 ConcurrentHashMap;

  • 其中还有 高低位拆分转移方式,可以查询资料去了解,在这里不讨论;

14. HashSet 有了解过吗?

  1. HashSet 实现了 Set 接口,仅存储对象;
  2. HashMap 实现了 Map 接口,存储的是键值对;
  3. HashSet 底层其实是用 HashMap 实现存储的;HashSet 封装了一系列 HashMap 的方法;依靠 HashMap 来存储元素值(利用 hashMap 的 key 键进行存储), 而 value 值默认为 Object 对象;
  4. 所以 HashSet 也不允许出现重复值,判断标准和 HashMap 判断标准相同, 两个元素的 hashCode 相等并且通过 equals() 方法返回 true;

15. HashTable 有了解过吗?

区别HashTableHashMap
数据结构数组 + 链表数组 + 链表 + 红黑树
是否可以为nullkey 和 value 都不能为 null可以为 null
hash算法key 的 hashCode()二次 hash
扩容方式当前容量翻倍 + 1当前容量翻倍
线程安全同步 (synchronized 加在方法上) 的,线程安全非线程安全

在实际开中不建议使用 HashTable,在多线程环境下可以使用 ConcurrentHashMap 类

  • 推荐文章

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

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

相关文章

守护Web安全:了解Web攻击与防护策略

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

搜索引擎都没流量啦,官网建设还有啥意义?

百度等搜索引擎都没啥流量了&#xff0c;再建设官网还有啥用&#xff1f;如果你把官网定位于获客&#xff0c;那真的没啥太大用处&#xff0c;但是官网不仅仅是用来获客的。 一、搜索引擎的流量被稀释了 搜索引擎流量减少的原因有多个&#xff0c; 1. 社交媒体的崛起&#xf…

嵌入式学习36-TCP要点及http协议

TCP发送文件的粘包问题 1. 例&#xff1a; 发端 1.flv-------->收端 1.flv csfga 2.解决 1. sleep&#xff08;1&#xff09; 延时发送 2.自…

HarmonyOS NEXT应用开发案例——二级联动

介绍 本示例主要介绍了List组件实现二级联动&#xff08;Cascading List&#xff09;的场景。 该场景多用于短视频中拍摄风格的选择、照片编辑时的场景的选择。 效果图预览 使用说明&#xff1a; 滑动二级列表侧控件&#xff0c;一级列表随之滚动。点击一级列表&#xff0c;…

蓝桥杯每日一题:烤鸡dfs

这道题考察了dfs的应用&#xff0c;题干十分有趣&#xff0c;思考过程对以后类似题目也有很强的参考性&#xff0c;一起来学习吧&#xff01; 题目&#xff1a; # 烤鸡 ## 题目背景 猪猪 Hanke 得到了一只鸡。 ## 题目描述 猪猪 Hanke 特别喜欢吃烤鸡&#xff08;本是同畜…

关于Linux上的$ORIGIN解说

1、Linux RPATH & $ORIGIN 许多现代C / C 项目都利用Autotools创建GNU构建系统&#xff0c;例如 根据平台生成make文件。 可执行文件&#xff08;二进制文件&#xff09;在生成/编译过程中生成&#xff0c;并且可以在执行编译的计算机上本地执行。 但是&#xff0c;如果将…

借着ChatGPT的人机交互聊聊长连接

ChatGPT这两年可谓风靡全球&#xff0c;尤其是最近Sora视频模型的横空出世以及claude 3模型所具备的浅意识&#xff0c;更是像打开了新世界的大门。本文就从ChatGPT的网页聊天开始聊起&#xff08;有蹭热度之嫌&#xff0c;哈哈&#xff09;&#xff0c;聊聊长连接的发展历程和…

程序员有哪些证书值得考?

证书可以作为第三方机构对于程序员特定技能或知识掌握程度的认可&#xff0c;在求职市场上&#xff0c;一些公司尤其是大型企事业单位或者政府项目可能更看重证书作为衡量应聘者专业能力的标准之一。备考证书的过程&#xff0c;也可以促使程序员系统地学习和巩固相关知识&#…

2024上半年软考中级《数据库系统工程师》报名考试全攻略

​2024年软考系统数据库系统工程师考试报名时间节点&#xff1a; 报名时间&#xff1a;上半年3月18日到4月15日&#xff0c;下半年8月19日到9月15日&#xff08;各地区报名时间不同&#xff0c;具体日期见官方通告&#xff09; 准考证打印时间&#xff1a;上半年5月20日起&am…

海云安荣获「粤港澳大湾区金融创新成果优秀解决方案」奖

近日&#xff0c;由广东省粤港澳合作促进会指导&#xff0c;广东省粤港澳合作促进会金融专业委员会、粤港澳大湾区金融创新研究院和澳门电子金融产业贸易促进会联合开展了“第二届金融创新优秀应用案例与解决方案技术成果评定”工作。海云安向组委会提交的“海云安开发者安全助…

python爬虫(3)

上一次的代码结果如下&#xff1a; 当然会有一点点不一样是正常的表现&#xff0c;因为这个图本身使用随机数rand函数做的&#xff0c;用其他两种随机函数出来的结果也不会完全相同。 继上节这次带来的是数组的重塑和转置 1、一维数组的重塑 在NumPy模块中的reshape()函数可…

人工蜂群算法

人工蜂群算法 人工蜂群算法&#xff08;Artificial Bee Colony Optimization,ABC&#xff09;是一种基于蜜蜂觅食行为的优化算法&#xff0c;由土耳其学者Karaboga于2005年提出&#xff0c;算法模拟蜜蜂的采蜜行为对优化问题进行求解。 算法原理 ABC算法的核心思想是将优化问…

Unreal Engine API:颠覆游戏开发,数字内容创造轻松驾驭!

&#x1f680; 原理介绍大揭秘 Epic Games的得意之作Unreal Engine API&#xff0c;是虚幻引擎跳动着的核心心脏。基于C架构&#xff0c;并携手可视化编程神器——蓝图系统&#xff0c;它为全球的游戏开发者们打造了一套火力全开的工具箱和功能丰富的接口。无论你是专业团队还…

C++vector的使用方法

文章目录 一、vector的介绍1. 文档链接2. 简要介绍 二、vector的使用1.vector的定义&#xff08;1&#xff09;构造函数&#xff08;2&#xff09;拷贝构造函数&#xff08;2&#xff09;赋值重载 2. vector 增删查改&#xff08;1&#xff09;operator []&#xff08;2&#x…

Vue3 中的代理原理详解

Vue3 中的代理原理详解 Vue3 中引入了代理&#xff08;Proxy&#xff09;机制&#xff0c;取代了 Vue2 中的 Object.defineProperty() 机制&#xff0c;用于实现数据响应式。代理机制是 ES6 中新增的特性&#xff0c;它可以用来自定义对象中的操作&#xff0c;比如属性查找、赋…

IDS入侵检测知识整理及lDS入侵检查表

【IDS入侵检测知识整理及lDS入侵检查表】 1. 网络入侵检测IDS概念 2. IDS分类 3. IDS的工作原理 4. IDS在网络中的部署 5. 入侵检查表 项目建设全套资料获取通道&#xff1a;软件开发全套资料_数字中台建设指南-CSDN博客

植物病虫害:YOLO水稻虫害识别数据集(6类,五千余张图像,标注完整)

YOLO水稻虫害识别数据集&#xff0c;包含褐飞虱&#xff0c;绿叶蝉&#xff0c;正常叶片&#xff0c;稻虫&#xff0c;二化螟&#xff0c;蝇蛆6个类别&#xff0c;共五千余张图像&#xff0c;yolo标注完整。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 …

【QT6】打开项目 .pro 一堆报错 但是程序可以运行 打开别人的QT项目后,全是报错

报错环境 我通过在网上拷贝的项目&#xff0c; 然后打开pro文件 build项目 你会发现各种报错 无缘无故的报错 明明环境已经没问题了 解决方案 首先是提示no valid settings file could be found&#xff0c;这个错误很好解决&#xff0c;删除项目目录下的.user文件&#xff…

第三百八十九回

文章目录 1. 概念介绍2. 使用方法2.1 获取所有时区2.2 转换时区时间 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享一些好的Flutter站点"相关的内容&#xff0c;本章回中将介绍timezone包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

制备大量单抗腹水就选博奥龙腹水专用佐剂

博奥龙Biodragon腹水专用佐剂是一种预先注入机体内&#xff0c;能增强机体对抗原的免疫应答能力或改变免疫应答类型的辅助物质。主要用于在单克隆抗体腹水制备中&#xff0c;在小鼠腹腔内接种杂交瘤细胞前&#xff0c;注射本佐剂到腹腔内&#xff0c;可以诱导杂交瘤细胞在腹腔内…