当前位置: 首页 > news >正文

【Java面试】十三、ArrayList相关

在这里插入图片描述
ArrayList、LinkedList、HashMap等集合,从其前缀可知其对应的数据结构为数组、链表、哈希表。从数据结构,也可反推出集合的结构。

文章目录

  • 1、算法复杂度分析
    • 1.1 时间复杂度
    • 1.2 常见复杂度
    • 1.3 空间复杂度
  • 2、数组
    • 2.1 内存寻址
    • 2.2 查找元素的时间复杂度
    • 2.2 增删元素的时间复杂度
  • 3、ArrayList源码
    • 3.1 成员变量部分
    • 3.2 构造方法部分
    • 3.3 添加数据和扩容
  • 4、ArrayList底层的实现原理
  • 5、实现数组和List之间的转换

1、算法复杂度分析

  • 时间复杂度:评估代码的执行耗时(与数据规模n的关系)
  • 空间复杂度:内存占用(与数据规模n的关系)

1.1 时间复杂度

在这里插入图片描述
以上,有3 * n + 3 行代码,假设每行执行耗费1ms,则总耗时:

T(n) = (3n + 3) * 1ms

时间复杂度,即表示代码执行时间与数据规模n变化的趋势 ⇒ 大O表示法 ⇒

T(n) = O(3n + 3)

因为表示的是一种"趋势",因此去掉系数和常数:

在这里插入图片描述
得出:

T(n) = O(n)

1.2 常见复杂度

总结:常对幂指阶

在这里插入图片描述

如O(1),性能最好,即数据变多,执行耗时还是不变,或者说代码行数是固定的。

如下:只要代码的执行时间不随着n的增大而增大,这样的代码复杂度都是O(1) ,第二个例子中,虽然有循环,但其次数固定,是100,是i < 100,而不是i < n,因此复杂度仍然为O(1)

在这里插入图片描述

例2:

在这里插入图片描述

例3:

在这里插入图片描述

此时,代码的执行和数据规模n的关系如下。因此,时间复杂度为O(log n)

在这里插入图片描述

同理,以下的实现复杂度也算为O(log n)

在这里插入图片描述

例4:O(n)复杂度的方法调用了O(log n)复杂度的方法,因此,test05方法的时间复杂度为O(n * log n)

在这里插入图片描述

1.3 空间复杂度

如下,两个局部变量i和sum,不管n等于多少,循环多少次,都占这两个变量的空间,因此,空间复杂度为O(1)

在这里插入图片描述

如下,数据规模n,影响数组长度,也即空间大小,因此,空间复杂度为O(n)

在这里插入图片描述

2、数组

2.1 内存寻址

连续的内存空间存储相同数据类型元素的线性数据结构。数组变量的值,指向0号元素的首地址。

在这里插入图片描述

取array[3]的值时,即计算索引为3的元素的内存地址:

//寻址
a[i] = baseAddress + i * dataTypeSize//baseAddress:数组首地址,如图中的10
//dataTypeSize:数组中元素类型的大小,如int时,该值为4(4 byte)

在这里插入图片描述
这也是数组下标从0开始的原因:让CPU少做一次减法运算

//寻址(下标从0开始)
a[i] = baseAddress + i * dataTypeSize//寻址(下标从1开始)
a[i] = baseAddress + (i - 1* dataTypeSize

2.2 查找元素的时间复杂度

根据索引查时,有寻址公式直接定位,复杂度为O(1)

在这里插入图片描述
未知索引,比如找值为55的这个元素。不排序,就得遍历,时间复杂度为O(n)。排序后二分查找,时间复杂度为O(log n)

2.2 增删元素的时间复杂度

数组是一段连续的空间,因此,插入或删除元素,其他元素会前移或者后退,时间复杂度为O(n)

在这里插入图片描述

3、ArrayList源码

3.1 成员变量部分

  • elementData这个Object类型的数组,是真正存储集合中元素的地方
  • size:元素个数

在这里插入图片描述

3.2 构造方法部分

无参构造,默认elementData是一个空数组{}。传入一个初始化容量的有参构造,逻辑为:传入的容量大于0时,给elementData复制一个对应长度的数组,等于0则给elementData赋值空数组

在这里插入图片描述

接收一个Collection(单列集合的父类)的参数,将 collection 对象转换成数组,然后将数组的地址的赋给 elementData

在这里插入图片描述

3.3 添加数据和扩容

添加数据和扩容的基本思路为:add前,先确保容量size + 1够不够,size为当前元素个数,size +1如果超过了elementData数组的长度,就需要扩容。扩容时,elementData长度 + elementData长度右移一位(除以2),然后将原elementData拷贝到新容量的elementData数组中

List<Integer> list = new ArrayList<>();
list.add(1);
for (int i = 2; i <= 10; i++) {list.add(i);
}
list.add(11);

以上,用了无参构造,因此,elementData是一个空数组{}。第一次add的时候:调用扩容方法的判断条件成立,扩容到10

在这里插入图片描述
往后,第2次 ~ 第10次add数据时,均不需扩容。比如第十次add:

在这里插入图片描述

第十一次add时:elementData长度为第一次扩容的10,而size + 1为11了,大于了elementData.length,扩容。新容量为

elementData.length + (elementData.length >> 1)
//10 + 10 >> 1 = 10 + 10/2 = 15

10扩容为15(约1.5倍),底层的elementData数组拷贝到一个长度为15的新数组

在这里插入图片描述

4、ArrayList底层的实现原理

  • ArrayList底层是一个数组(elementData属性)
  • ArrayList初始容量为0(elementData为空数组{}),当第一次添加数据时,才会初始化容量为10
  • ArrayList扩容的时候,容量为原容量的1.5倍,且每次扩容都需要拷贝数组

调用add添加数据的时候,逻辑如下:

  • 确保能存下 下一个数据,判断逻辑是数组已使用长度(size) +1 后是否大于elementData数组的长度
  • size +1 > elementData.length则调用grow方法扩容
  • 反之,则直接放进去
ArrayList myList = new ArrayList(10);

以上写法,list扩容0次,因为指定了容量为10,elementData数组不再是空数组{ },因此,第一次add时不会再扩容。

在这里插入图片描述

5、实现数组和List之间的转换

在这里插入图片描述

  • 数组转List,使用java.util.Arrays工具类的asList方法
  • List转数组,调用其toArray方法,传参为带list长度的一个空数组

用 Arrays.asList 将数组转List 后,如果修改了数组内容,则由数组转来的List也会跟着变

测试代码:

在这里插入图片描述

原因:Arrays工具类底层用静态内部类ArrayList,将传入的数组进行了包装,最终指向的都是同一个内存地址。也就是说,数组转List后,List底层的数组,还是指向原数组

在这里插入图片描述

调用toArray方法,将List转为数组,此时再修改List,由List转来的数组并不跟着变

原因:调用了 toArray 以后,返回的是对ArrayList的elementData数组进行的拷贝

在这里插入图片描述

相关文章:

【Java面试】十三、ArrayList相关

ArrayList、LinkedList、HashMap等集合&#xff0c;从其前缀可知其对应的数据结构为数组、链表、哈希表。从数据结构&#xff0c;也可反推出集合的结构。 文章目录 1、算法复杂度分析1.1 时间复杂度1.2 常见复杂度1.3 空间复杂度 2、数组2.1 内存寻址2.2 查找元素的时间复杂度2…...

网络简史-基于图论的网络

先看一幅图&#xff1a; 如图&#xff0c;我们对类似 crossbar&#xff0c;banyan tree&#xff0c;b-tree&#xff0c;10-tree&#xff0c;256-tree&#xff0c;甚至 dcn fat-tree 等 “规则拓扑” 网络相当熟悉。规则拓扑网络中&#xff0c;地址信息被编码到拓扑本身&#…...

Git工作机制,暂存区,本地库,远程库管理,常用命令

文章目录 工作机制1. 本地库&#xff0c;暂存区管理2. 分支管理3. 远程库管理 工作机制 工作区&#xff08;写代码&#xff09; ----> 暂存区&#xff08;临时存储&#xff09; ----> 本地库&#xff08;历史版本&#xff09; ----> 远程库&#xff08;GitLab、GitHub…...

找不到steam_api64.dll,无法继续执行的原因及解决方法

电脑已经成为我们生活中不可或缺的一部分。然而&#xff0c;在使用电脑的过程中&#xff0c;我们经常会遇到一些常见的问题&#xff0c;其中之一就是找不到某个特定的动态链接库文件&#xff0c;比如steamapi64.dll。这个问题可能会导致某些应用程序无法正常运行&#xff0c;给…...

鸿蒙开发接口定制管理:【@ohos.enterpriseDeviceManager (企业设备管理)】

企业设备管理 说明&#xff1a; 本模块首批接口从API version 9开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import enterpriseDeviceManager from ohos.enterpriseDeviceManager;enterpriseDeviceManager.activateAdmin activate…...

Pytorch实用教程:多分类任务中使用的交叉熵损失函数nn.CrossEntropyLoss

nn.CrossEntropyLoss 在 PyTorch 中是处理多分类问题的常用损失函数,它是两个函数 nn.LogSoftmax 和 nn.NLLLoss(Negative Log Likelihood Loss)的组合。使用这个损失函数可以直接从模型得到原始的输出分数(logits),而不需要单独对输出进行 Softmax 处理。下面详细介绍这…...

智慧冶金:TSINGSEE青犀AI+视频技术助力打造高效、安全的生产环境

一、建设背景 冶金行业因其特殊的生产环境和工艺要求&#xff0c;对安全生产、环境保护以及质量监控等方面有着极高的要求。因此&#xff0c;将视频智能监控技术引入冶金行业&#xff0c;不仅有助于提升生产效率&#xff0c;更能有效保障生产安全&#xff0c;降低事故风险。 …...

【ARM+Codesys案例】基于全志T3+Codesys软PLC的3C点胶边缘控制解决方案:整合了运动控制、视觉、激光测高等技术

视觉精密点胶控制方案 针对直交型机构的平面点涂胶应用&#xff0c;基于CODESYS软件平台开发的一站式PC型控制器解决方案&#xff0c;包含运动控制器硬件和点胶应用软件。方案整合了运动控制、视觉、激光测高等技术&#xff0c;高效精密的控制胶水点涂于产品表面或内部&#x…...

描述JSP的内置对象

JSP&#xff08;JavaServer Pages&#xff09;内置对象&#xff08;也称为隐式对象或预定义对象&#xff09;是JSP容器为每个页面提供的Java对象&#xff0c;开发者可以直接在JSP页面中使用它们&#xff0c;而无需显式声明。这些内置对象提供了对JSP页面运行环境信息的快速访问…...

MongoDB CRUD操作:可重试写入

MongoDB CRUD操作&#xff1a;可重试写入 文章目录 MongoDB CRUD操作&#xff1a;可重试写入使用的先决条件部署的限制支持的存储引擎3.6 MongoDB 驱动程序MongoDB 版本写确认 可重试写入和多文档事务启用可重试写入MongoDB驱动mongosh 可重试的写操作行为持续的网络错误故障切…...

Microsoft Outlook Lite 引入短信功能

随着科技的不断进步&#xff0c;我们的沟通方式也在不断演变。微软最新推出的 Outlook Lite 应用&#xff0c;不仅为我们提供了一个轻量级的电子邮件管理工具&#xff0c;现在更是带来了一项令人兴奋的新功能——短信服务。 Outlook Lite&#xff1a;轻量级&#xff0c;功能全…...

Redis的数据结构以及对应的使用场景

Redis支持的数据结构包括字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(Sorted Set)等。这些数据结构在应用开发中扮演着重要的角色&#xff0c;它们各自适用于不同的使用场景和需求。以下是对Redis各数据结构的详细分析及它们的使用场景&#xff1a; 字符串(S…...

Vue中如何获取dom元素?

在Vue中&#xff0c;通常我们不直接操作DOM元素&#xff0c;因为Vue是一个声明式渲染的框架&#xff0c;它鼓励我们使用数据驱动视图的方式来更新UI。然而&#xff0c;在某些情况下&#xff0c;你可能需要直接访问DOM元素。在这种情况下&#xff0c;你可以使用Vue的ref属性和$r…...

前端最新面试题(基础模块HTML/CSS/JS篇)

目录 一、HTML、HTTP、WEB综合问题 1 前端需要注意哪些SEO 2 img的title和alt有什么区别 3 HTTP的几种请求方法用途 4 从浏览器地址栏输入url到显示页面的步骤 5 如何进行网站性能优化 6 HTTP状态码及其含义 7 语义化的理解 8 介绍一下你对浏览器内核的理解? 9 html…...

matlab模拟太阳耀斑喷发

代码 function simulate_solar_flare% 参数设置gridSize 100; % 网格大小timeSteps 200; % 时间步数dt 0.1; % 时间步长% 初始化网格[X, Y] meshgrid(linspace(-5, 5, gridSize));Z zeros(size(X));% 设置耀斑初始位置和强度flareCenter [0, 0]; % 耀斑中心位置flareRad…...

WebStorm 2024.1.1 Mac激活码 前端开发工具集成开发环境(IDE)

WebStorm 2024 Mac激活码 搜索Mac软件之家下载WebStorm 2024 Mac激活版 WebStorm 2024 功能介绍 WebStorm 2024是由JetBrains公司开发的一款专为前端开发设计的集成开发环境&#xff08;IDE&#xff09;。它提供了一整套功能&#xff0c;旨在提高Web开发者的工作效率和代码质…...

多项目的.net core解决方案(项目间引用)如何使用Docker部署

解决方案内部项目之间引用很正常&#xff0c;但我docker不是很熟&#xff0c;对一些基础命令含义还理解不深入&#xff0c;部署引用其他项目的项目总不成功。搜到了一篇非常适合初学者&#xff0c;从dockerfile命令讲解&#xff0c;到解决引用其他项目时如何docker部署的文章。…...

使用raise语句抛出异常

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 如果某个函数或方法可能会产生异常&#xff0c;但不想在当前函数或方法中处理这个异常&#xff0c;则可以使用raise语句在函数或方法中抛出异常。rai…...

vue组件中data为什么必须是一个函数?

在 Vue 中&#xff0c;组件的 data 必须是一个函数&#xff0c;而不是一个对象&#xff0c;这是为了保证每个组件实例都可以维护一份被返回对象的独立的拷贝。如果 data 是一个对象&#xff0c;那么所有的组件实例将共享同一个引用&#xff0c;导致一个组件实例的数据变化会影响…...

10-Django项目--Ajax请求

目录 Ajax请求 简单示范 html 数据添加 py文件 html文件 demo_list.html Ajax_data.py 图例 Ajax请求 简单示范 html <input type"button" id"button-one" class"btn btn-success" value"点我"> ​ ​ <script>/…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...