Java-数据结构(三)-List:ArrayList和LinkedList及其相关面试题

目录

  • 一、引言
  • 二、ArrayList
    • 2.1 ArrayList是什么?
    • 2.2 ArrayList的历史由来
    • 2.3 ArrayList的使用好处
    • 2.4 ArrayList的底层原理
    • 2.5 ArrayList的操作方法及代码示例
  • 三、LinkedList
    • 3.1 LinkedList是什么?
    • 3.2 LinkedList的历史由来
    • 3.3 LinkedList的使用好处
    • 3.4. LinkedList的底层原理
    • 3.5 LinkedList的操作方法及代码示例
  • 四、表格对比二者区别
  • 五、相关面试题

一、引言

    ArrayList和LinkedList是Java集合框架中常用的两种列表实现。它们都实现了List接口,提供了类似于数组的数据结构,可以按照索引访问和操作元素,以及支持动态调整大小。然而,两者在内部实现和性能方面有所不同。

    在本文中,我们将探讨ArrayList和LinkedList的内部实现原理、常用操作的性能特点以及适用场景的选择依据。通过了解它们的区别和使用场景,你将能够更加理解和灵活地运用它们来满足不同的开发需求。

二、ArrayList

在这里插入图片描述

2.1 ArrayList是什么?

    ArrayList是Java集合框架中的一种实现类,它实现了List接口,提供了一个动态数组的实现。

2.2 ArrayList的历史由来

    ArrayList的历史由来可以追溯到Java 1.2版本。在早期的Java版本中,Java提供了Vector(向量)类来表示动态数组。然而,Vector类的设计存在一些性能和同步问题,因此Java开发团队决定引入一个新的类来替代Vector,即ArrayList。

    ArrayList的设计目标是提供一种高效的动态数组实现,以满足开发者在处理大量数据时的需求。相比于Vector,ArrayList具有更好的性能和可扩展性。它可以动态调整大小,支持随机访问,同时还提供了一系列的常用操作方法,如添加、删除、查找等。

2.3 ArrayList的使用好处

  • 快速访问: 由于ArrayList实现了动态数组,可以通过索引非常快速地访问和修改元素。
  • 方便的插入和删除: ArrayList可以通过调整数组大小来实现元素的插入和删除操作,这样不会导致其他元素的移动。
  • 可变大小: ArrayList的大小是可变的,可以根据需要动态调整。

2.4 ArrayList的底层原理

    ArrayList是基于数组实现的动态数组,它的底层原理主要包括以下几个要点:

    1、内部数组:ArrayList使用一个内部数组来存储元素。这个数组是一个连续的内存块,通过索引可以直接访问元素。默认情况下,ArrayList会初始化一个初始大小的数组,当元素数量超过数组大小时,会自动进行扩容。

    2、动态扩容:当ArrayList的元素数量超过数组大小时,会触发自动扩容操作。ArrayList通过创建一个更大的新数组,并将原数组的元素复制到新数组中来实现扩容。通常情况下,新数组的大小会是原数组大小的一倍,以实现平均时间复杂度为O(1)的插入操作。

    3、连续内存:由于ArrayList使用连续的内存,因此在进行元素的插入和删除操作时,可能需要进行大量的元素移动。例如,在数组的中间位置插入一个元素会导致插入位置后面的所有元素都向后移动一个位置。同样地,删除一个元素可能需要将后面的所有元素向前移动一个位置。这种情况下,插入和删除操作的时间复杂度为O(n),其中n是数组中的元素数量。

    4、随机访问:由于ArrayList是基于数组实现的,所以支持高效的随机访问。通过索引,可以以O(1)的时间复杂度直接访问数组中的元素。

2.5 ArrayList的操作方法及代码示例

import java.util.ArrayList;public class ArrayListExample {public static void main(String[] args) {// 创建ArrayListArrayList<String> arrayList = new ArrayList<>();// 添加元素arrayList.add("Apple");arrayList.add("Banana");arrayList.add("Orange");// 获取元素String firstElement = arrayList.get(0);System.out.println("第一个元素是:" + firstElement); // Output: 第一个元素是:Apple// 修改元素arrayList.set(1, "Grapes");System.out.println("修改后的元素是:" + arrayList); // Output: 修改后的元素是:[Apple, Grapes, Orange]// 删除元素arrayList.remove(2);System.out.println("删除后的元素是:" + arrayList); // Output: 删除后的元素是:[Apple, Grapes]}
}

三、LinkedList

在这里插入图片描述

3.1 LinkedList是什么?

    LinkedList是Java中的一个双向链表实现的类,同样也实现了List接口。LinkedList的节点包含了对前一个节点和后一个节点的引用,允许以O(1)的时间复杂度在任意位置插入和删除元素。

3.2 LinkedList的历史由来

    链表(LinkedList)的历史由来可以追溯到计算机科学的早期。链表是一种基本的数据结构,用于在内存中组织和管理数据。链表最早在20世纪60年代被引入到计算机科学中,作为一种替代数组的数据结构。

3.3 LinkedList的使用好处

  • 高效的插入和删除操作: 由于LinkedList是双向链表的实现,插入和删除操作只需要改变节点之间的引用,不需要像ArrayList那样调整数组大小。
  • 非常适合频繁的插入和删除操作: LinkedList对于频繁的插入和删除操作表现更加高效。
  • 实现了Queue和Deque接口: LinkedList还实现了Queue和Deque接口,可以作为队列和双端队列使用。

3.4. LinkedList的底层原理

    LinkedList内部通过双向链表来存储元素。每个节点包含了一个元素和对前一个节点和后一个节点的引用。底层原理主要包括以下几个要点:

    1、节点类:LinkedList中的每个元素被封装成一个节点对象,这个节点对象包含了数据和两个指针,即前驱指针和后继指针。通过前驱指针和后继指针,可以在链表中实现元素的插入、删除和访问操作。

    2、头节点和尾节点:LinkedList中有两个特殊的节点,即头节点和尾节点。头节点是链表的第一个节点,尾节点是链表的最后一个节点。它们分别通过头指针和尾指针指向链表的首尾。

    3、双向链表:每个节点都包含一个指向前一个节点的指针和一个指向后一个节点的指针,这样的链表结构就是双向链表。双向链表可以实现双向遍历,即可以从头节点向后一个个遍历,也可以从尾节点向前一个个遍历。

    4、插入操作:在LinkedList进行插入操作时,会创建一个新的节点对象,并调整相邻节点的指针指向。例如,在链表的中间位置插入一个元素,需要先创建一个新的节点对象,然后将新节点的前驱指针指向插入位置的前一个节点,将新节点的后继指针指向插入位置的后一个节点,最后调整相邻节点的指针指向新节点。

    5、删除操作:在LinkedList进行删除操作时,会通过调整相邻节点的指针指向来删除指定节点。例如,在链表中删除一个节点,只需要将被删除节点的前驱指针指向被删除节点的后一个节点,将被删除节点的后继指针指向被删除节点的前一个节点,最后将被删除节点对象回收。

3.5 LinkedList的操作方法及代码示例

import java.util.LinkedList;public class LinkedListExample {public static void main(String[] args) {// 创建LinkedListLinkedList<String> linkedList = new LinkedList<>();// 添加元素linkedList.add("Apple");linkedList.add("Banana");linkedList.add("Orange");// 获取元素String firstElement = linkedList.getFirst();System.out.println("第一个元素是:" + firstElement); // Output: 第一个元素是:Apple// 修改元素linkedList.set(1, "Grapes");System.out.println("修改后的元素是:" + linkedList); // Output: 修改后的元素是:[Apple, Grapes, Orange]// 删除元素int elementToRemove = 20;boolean removeResult = linkedList.remove(Integer.valueOf(elementToRemove));if (removeResult) {System.out.println("成功删除元素:" + elementToRemove);} else {System.out.println("无法删除元素:" + elementToRemove);}System.out.println("修改后的链表:" + linkedList);}
}

四、表格对比二者区别

在这里插入图片描述

五、相关面试题

  1. ArrayList和LinkedList的区别是什么?
        答:ArrayList是基于数组实现的,它在内存中是连续存储的,支持对元素的随机访问和快速插入/删除操作。LinkedList是基于链表实现的,它在内存中的元素是通过指针连接的,支持高效的插入/删除操作,但随机访问元素的性能较差。

  2. 如何选择ArrayList或LinkedList?
        答:如果需要频繁执行随机访问元素的操作,并且对于插入和删除操作的性能要求不高,可以选择ArrayList。如果需要频繁执行插入和删除操作,而对于随机访问的需求不太高,可以选择LinkedList。

  3. ArrayList和LinkedList的插入和删除操作的时间复杂度是多少?
        答:对于ArrayList,插入和删除操作的时间复杂度是O(n),因为在数组中需要移动元素。对于LinkedList,插入和删除操作的时间复杂度是O(1),因为只需修改指针即可。

  4. ArrayList和LinkedList的查找操作的时间复杂度是多少?
        答:对于ArrayList,查找操作的时间复杂度是O(1),因为可以通过索引直接访问数组中的元素。对于LinkedList,查找操作的时间复杂度是O(n),因为需要从头节点开始遍历链表找到目标元素。

  5. 在什么情况下应该使用ArrayList,而在什么情况下应该使用LinkedList?
        答:当需要频繁执行随机访问元素的操作或者仅需要在末尾进行插入和删除时,应该使用ArrayList。当需要频繁执行插入和删除操作,或者需要在其他位置插入和删除元素时,应该使用LinkedList。

  6. ArrayList和LinkedList在空间复杂度方面有什么区别?
        答:ArrayList的空间复杂度是O(n),其中n是存储的元素数量,因为它需要一个连续的数组来存储元素。LinkedList的空间复杂度也是O(n),但在实际使用中,它可能更占用内存,因为除了存储元素本身外,还需要额外的指针来连接元素。

如果本篇博客对您有一定的帮助,请您留下宝贵的三连:留言+点赞+收藏哦。

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

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

相关文章

MySQL事务相关笔记

杂项 InnoDB最大特点&#xff1a;支持事务和行锁&#xff1b; MyISAM不支持事务 介绍 一个事务是由一条或者多条对数据库操作的SQL语句所组成的一个不可分割的单元&#xff0c;只有当事务中的所有操作都正常执行完了&#xff0c;整个事务才会被提交给数据库。事务有如下特性…

大数据面试题-场景题

1.手写Flink的UV 手写Flink的UV 2.Flink的分组TopN Flink的分组TopN 3.Spark的分组TopN 1&#xff09;方法1&#xff1a; &#xff08;1&#xff09;按照key对数据进行聚合&#xff08;groupByKey&#xff09; &#xff08;2&#xff09;将value转换为数组&#xff0c;利…

银河麒麟服务器v10 sp1 安装mysql

可以先用 dpkg --list|grep mysql 查看自己的mysql有哪些依赖&#xff1a; 上图已经是安装后的截图&#xff0c;然后再卸载 sudo apt-get autoremove --purge mysql-common 本文在没有安装之前&#xff0c;只有mysql-common包&#xff0c;再用dpkg --list|grep mysql查看&…

联邦学习中的模型聚合

目录 联邦学习中的模型聚合 1.client-server 算法 2. fully decentralized(完全去中心化)算法 联邦学习中的模型聚合 在联邦学习的情景下引入了多任务学习&#xff0c;其采用的手段是使每个client/task节点的训练数据分布不同&#xff0c;从而使各任务节点学习到不同的模型…

ELK增量同步数据【MySql->ES】

一、前置条件 1. linux&#xff0c;已经搭建好的logstasheskibana【系列版本7.0X】&#xff0c;es 的plugs中安装ik分词器 ES版本&#xff1a; Logstash版本&#xff1a; &#xff08;以上部署&#xff0c;都是运维同事搞的&#xff0c;我不会部署&#xff0c;同事给力&#…

Neighborhood Contrastive Learning for Novel Class Discovery (CVPR 2021)

Neighborhood Contrastive Learning for Novel Class Discovery (CVPR 2021) 摘要 在本文中&#xff0c;我们解决了新类发现(NCD)的问题&#xff0c;即给定一个具有已知类的有标签数据集&#xff0c;在一组未标记的样本中揭示新的类。我们利用ncd的特性构建了一个新的框架&am…

JMeter之事务控制器实践

目录 前言 事务控制器 JMeter控制器添加路径&#xff1a; Generate parent sample 1、不勾选任何选项&#xff1a; 2、勾选【Generate parent sample】 3、Include duration of timer and pre-post processors in generated sample 小结 前言 在JMeter中&#xff0c;事…

Linux下GO IDE安装和配置(附快捷键)

目前&#xff0c;GoLand、VSCode 这些 IDE 都很优秀&#xff0c;但它们都是 Windows 系统下的 IDE。在 Linux 系统下我们可以选择将 Vim 配置成 Go IDE。熟练 Vim IDE 操作之后&#xff0c;开发效率不输 GoLand 和 VSCode。有多种方法可以配置一个 Vim IDE&#xff0c;这里我选…

基于免疫优化算法的物流配送中心选址规划研究(Matlab实现)

目录 1 概述 2 物流配送中心选址规划研究 3 Matlab代码 4 结果 1 概述 影响物流配送中心选址的因素有很多,精确选址优化问题亟待解决。通过充分考虑货物的配送时间,将免疫算法加入其中,介绍了物流配送选址模型的构建以及免疫算法实现的相关步骤,最后利用matlab软件进行分析,提出…

UE5.2 LyraDemo源码阅读笔记(二)

UE5.2 LyraDemo源码阅读笔记&#xff08;二&#xff09; 创建了关卡中的体验玩家Actor和7个体验玩法入口之后。 接下来操作关卡中的玩家与玩法入口交互&#xff0c;进入玩法入口&#xff0c;选择进入B_LyraFrontEnd_Experience玩法入口&#xff0c;也就是第3个入口。触发以下请…

web学习1--maven--项目管理工具

写在前面&#xff1a; 这学期搞主攻算法去了&#xff0c;web的知识都快忘了。开始复习学习了。 文章目录 maven介绍功能介绍maven安装jar包搜索仓库 pom文件项目介绍父工程依赖管理属性控制可选依赖构建 依赖管理依赖的传递排除依赖可选依赖 maven生命周期分模块开发模块聚合…

算法的时间复杂度

算法的时间复杂度 什么是时间复杂度 时间复杂度是衡量算法执行时间随输入规模增长而增长的度量标准。它描述了算法运行时间与问题规模之间的关系&#xff0c;用于评估算法的效率和性能。 通常情况下&#xff0c;时间复杂度表示为大O符号&#xff08;O&#xff09;&#xff0…