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

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.mzph.cn/news/731007.shtml

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

相关文章

git - 笔记

为什么要学习Git 为什么要学习Git软件 为什么学习 因为在主流开发中&#xff0c;基于互联网软件开发的项目都会使用Git软件来进行项目开发过程中的资源管理 比如人力资源 代码资源 比如前端资源 .html .java等代码资源 文档资源 像项目开发中涉及到的需求文档等 这种项目中管理…

Langchain-Chatchat本地搭建ChatGLM3模型和提取PDF内容

文章目录 1、软件要求2、安装CUDA2.1、安装gcc2.2、安装CUDA 3、安装Anaconda33.1、下载Anaconda33.2、创建python虚拟环境 4、部署系统4.1、下载源码4.2、安装依赖4.3、下载模型4.4、初始化配置和知识库4.4.1、初始化配置4.4.2、初始化知识库 4.5、运行4.6、运行4.6.1、启动4.…

Qt初识 - 编辑框 | 按钮 | 命名规范

目录 一、编辑框 (一) Designer中的编辑框 (二) Code中的编辑框 二、按钮 (一) Designer中的按钮 (二) Code中的按钮 三、Qt中的命名规范 一、编辑框 (一) Designer中的编辑框 进入到Designer界面中 找到Input Widgets目录 找到该目录下的 将这个控件拉出去 双击就可…

神经网络softmax算法与卷积层

多类分类&#xff1a; 多类是分类算法中的一种&#xff0c;它区别于我们的0&#xff0c;1这样子的二进制分类&#xff0c;它会有多个分类的标签&#xff0c;让我们去取其中的一个。 softmax函数&#xff1a; softmax回归算法是我们的sigmoid回归的推广。 上图就是softmax运…

Koa: 打造高效、灵活的Node.js后端 (介绍与环境部署)

在上一篇文章中&#xff0c;我们了解了Node.js的基础知识&#xff0c;今天我们将进一步学习Node.js 较新的一个轻量级Web框架Koa&#xff0c;一起创建NodeJS后端服务器吧&#xff01; 一、介绍 Koa是一个新生代Node.js Web框架&#xff0c;由Express原团队成员开发&#xff0c…

SpringBootWeb(接收请求数据,返回响应结果,分层解耦,Spring的IOCDI)【详解】

目录 一、接收请求数据 1. 接收表单参数 1.原始方式【了解】 2.SpringBoot方式 3.参数名不一致RequestParam 2.实体参数 1.简单实体对象 2.复杂实体对象 3.数组集合参数 4.日期参数 3. JSON参数 1.Postman发送JSON数据 2.服务端接收JSON数据 4. 路径参数(rest风格…

ChatGPT Plus 自动扣费失败,如何续订

ChatGPT Plus 自动扣费失败&#xff0c;如何续订 如果您的 ChatGPT Plus 订阅过期或扣费失败&#xff0c;本教程将指导您如何重新订阅。 本周更新 ChatGPT Plus 是一种每月20美元的订阅服务。扣费会自动进行&#xff0c;如果您的账户余额不足&#xff0c;OpenAI 将在一次扣费…

USB2.0设备检测过程信号分析

1.简介 USB设备接入的Hub端口负责检测USB2.0设备是否存在和确定USB2.0设备的速度。检测设备是否存在和确定设备速度涉及一系列的信号交互&#xff0c;下面将分析该过程。 2.硬件 USB低速设备和全速/高速设备的连接器在硬件结构上有所不同&#xff0c;而主机或者Hub接收端连接…

C++11_右值引用与移动语义

目录 1、左值的定义 1.1 左值引用 2、右值的定义 2.1 右值引用 3、右值与左值的使用区别 4、右值引用的意义 4.1 左值引用的短板 5、移动语义 5.1 移动构造 5.2 移动赋值 6、万能引用 6.1 右值的别名-左值化 6.2 完美转发 前言&#xff1a; 在C11之前就有了引…

地址分词 | EXCEL批量进行地址分词,标准化为十一级地址

一 需求 物流需要对用户输入地址进行检查&#xff0c;受用户录入习惯地址可能存在多种问题。 地址标准化是基于地址引擎和地址大数据模型&#xff0c;自动将地址信息标准化为省、市、区市县、街镇、小区、楼栋、单元、楼层、房屋、房间等元素&#xff0c;补充层级缺失数据、构建…

bug - poi getMergedRegion合并后的行列number错误

第一个CellRangeAddress 的Row number 应该是0&#xff0c;但是给出的是1。 其它的CellRangeAddress 与实际大致相差4-5不等&#xff0c;没有规律。 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>…

ChatGPT Plus 支付出现「您的银行卡被拒绝/your card has been declined」怎么办?

ChatGPT Plus 支付出现「您的银行卡被拒绝/your card has been declined」怎么办&#xff1f; 在订阅 ChatGPT Plus 或者 OpenAI API 时&#xff0c;有时候会出现已下报错 &#xff1a; Your card has been declined. 您的银行卡被拒绝 出现这种错误&#xff0c;有以下几个解…

网关数据采集解决方案-天拓四方

随着物联网技术的快速发展&#xff0c;数据采集已成为企业运营、管理和决策的重要支撑。网关作为连接不同网络的关键设备&#xff0c;其在数据采集过程中发挥着至关重要的作用。本文将详细介绍一种网关数据采集解决方案&#xff0c;旨在确保数据采集的高效性、准确性和安全性。…

在圆钢生产中 哪种直线度测量仪更具实用性?

圆钢直线度尺寸是其品质检测中重要一环&#xff0c;要说直线度测量方法&#xff0c;那肯定是有很多种&#xff0c;但要说适合产线&#xff0c;更具实用性的是哪种&#xff0c;本文就来简单的看一下。 简单来说&#xff0c;直线度测量方法有直尺法、重力法、直线法、百分表、水平…

入门C++《类与对象》————2

目录 前言&#xff1a; 1.类的6个默认成员函数 2. 构造函数 1、概念引入&#xff1a; 2、特性&#xff1a; 3.析构函数 1、概念引入&#xff1a; 2、特性&#xff1a; 4.拷贝构造函数 1、概念&#xff1a; 2、特征&#xff1a; 5.赋值运算符重载 1、运算符重载&am…

Word论文格式怎么设置 Word论文查重功能在哪里 论文格式要求及字体大小 论文查重怎么查 WPS论文查重准确吗

Word文档是由Microsoft Word处理软件创建和编辑的文档。Word文档通常用于创建各种类型的文档&#xff0c;如信函、报告、简历、论文等。本篇文章将为大家介绍Word论文格式怎么设置以及Word论文查重功能在哪里。 一、Word论文格式怎么设置 一个好的论文格式&#xff0c;是论文…

机器学习——神经网络压缩

神经网络压缩 需要部署&#xff0c;设备内存和计算能力有限&#xff0c;需要进行模型压缩&#xff0c;在设备上运行的好处是低延迟&#xff0c;隐私性。 目录 不考虑硬件问题&#xff0c;只考虑通过软件算法优化。 修剪网络 参数过多或者没有用的参数&#xff0c;可以将其剪…

Missing type map configuration or unsupported mapping

今天开发的时候突然遇到这么一个问题&#xff0c;可以确定的是不是AutoMap的问题&#xff0c;因为项目中其他接口都是好好的&#xff0c;只有新加的这个控制器不行&#xff0c;排查了一下&#xff0c;少了映射配置&#xff0c;在这里加上映射关系即可&#xff0c;大意了。

【Unity】ABB CRB 15000 外部引导运动

一、RobotStudio控制器的文件系统和配置参数 HOME&#xff1a;控制器文件系统的根目录或起始点。配置&#xff1a;机器人控制器的配置设置和参数。外件信息&#xff1a;连接到机器人的外部组件的信息。I/O 系统&#xff1a;输入/输出系统&#xff0c;管理机器人和外部设备之间的…

JavaScript 入门手册(一)

目录 一、JavaScript 是什么? 1.1 JavaScript 介绍 1.2 JavaScript 与 ECMAScript 的关系 1.3 JavaScript 是脚本语言 1.4 JavaScript 的特点 1.5 运行 JavaScript 1.6 保留关键字 二、Node.js 是什么&#xff1f; 2.1 运行时是什么&#xff1f; 2.2 Node.js 的组成…