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

news2024/12/23 4:53:08

目录

  • 一、引言
  • 二、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) {
        // 创建ArrayList
        ArrayList<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) {
        // 创建LinkedList
        LinkedList<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.coloradmin.cn/o/718110.html

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

相关文章

攻防世界_web

robots 题目描述是这样的&#xff0c;虽然这是一道基础题&#xff0c;但我确实还没有了解过robots协议 第一次知道是被御剑给扫描出来的后台文件 这次直接访问看看 初级题就是初级题&#xff0c;访问后得到提示&#xff0c;如果没做过我估计还不知道该咋整&#xff0c;这也是一…

Squid 缓存代理(一)---原理及搭建(传统代理、透明代理)

前言 Squid 是 Linux 系 统 中 最 常 用 的 一 款 开 源 代 理 服 务 软 件 &#xff08; 官 方 网 站 为 http://www.squid-cache.org&#xff09;&#xff0c;可以很好地实现 HTTP 和 FTP&#xff0c;以及 DNS 查询、SSL 等应用的缓存代理。缓存代理作为应用层的代理服务软件…

C#(四十八)之StreamWriter StreamWriter使用方法及与FileStream类的区别

StreamReader类的属性&#xff1a; CurrentEncoding&#xff1a;获取流使用的字符编码 EndOfStream&#xff1a;指示当前位置是否在流的末尾 StreamReader类的方法&#xff1a; Read()&#xff1a;读取流中的下一个字符或下一组字符。 ReadBlock()&#xff1a;读取一个字符…

使用Maven对Scala独立应用程序进行编

任务描述 本关任务&#xff1a;使用Scala编写一个找出README.md文件中包含a的行数和包含b的行数的程序&#xff0c;并使用Maven对程序进行编译打包提交到Saprk上。 相关知识 在终端中执行如下命令创建一个文件夹 sparkapp3作为应用程序根目录&#xff1a; cd ~ # 进入用户主…

银河麒麟服务器v10 sp1 redis开机自动启动

接上一篇&#xff1a;银河麒麟服务器v10 sp1 安装 redis_csdn_aspnet的博客-CSDN博客 将redis_init_script文件复制到/etc/init.d下&#xff0c;重命名为redisd&#xff1a; rootxxx-pc:cp /usr/local/redis/redis-7.0.11/utils/redis_init_script /etc/init.d/redisd 内容如…

可视化网页设计工具 Blocs「Mac」

Blocs是一款用于网页设计和开发的可视化工具。它提供了一个直观且强大的界面&#xff0c;使用户可以轻松地创建精美的网页&#xff0c;而无需编写代码。 使用Blocs&#xff0c;您可以通过拖放元素、调整布局、编辑文本和图像等来构建网页。它提供了丰富的预设组件和模板&#x…

科幻大作【InsCode Stable Diffusion美图活动一期】

一、 Stable Diffusion 模型在线使用地址&#xff1a; https://inscode.csdn.net/inscode/Stable-Diffusion 二、模型相关版本和参数配置&#xff1a; Model: GuoFeng3, Version: v1.2.0 迭代步数:30 采样方法:DPM 2M Karras 或者 DPM 2M SDE Karras3 宽高&#xff1a;10…

Kubernetes入门实战课-k8s实验环境

Kubernetes入门实战课-k8s实验环境 文章目录 Kubernetes入门实战课-k8s实验环境docker 架构图 回顾Kubernetes 作用minikube小型测试环境Kubernetes命令行工具kubectlminikube 安装过程minikube 环境示意图Kubernetes 和 Docker 之间有什么区别&#xff1f; docker 架构图 回顾…

ModaHub魔搭社区:详解GPTCache 系统的五个主要组件

目录 LLM 适配器&#xff08;LLM Adapter&#xff09; Embedding 生成器&#xff08;Embedding Generator&#xff09; 缓存管理器&#xff08;Cache Manager&#xff09; 相似性评估器 &#xff08;Similarity Evaluator&#xff09; 后期处理器&#xff08;Post Process…

Flink DataStream之从Kafka读数据

搭建Kafka 参考&#xff1a;centos7下kafka2.12-2.1.0的安装及使用_kafka2.12-2.1.0 steam_QYHuiiQ的博客-CSDN博客 启动zookeeper [rootlocalhost kafka_2.12-2.8.1]# pwd /usr/local/wyh/kafka/kafka_2.12-2.8.1 [rootlocalhost kafka_2.12-2.8.1]# ./bin/zookeeper-server…

Windows 环境下Docker 安装伪分布式 Hadoop

Windows 环境下Docker 安装伪分布式 Hadoop 1、环境2、拉取镜像3、启动容器4、预备操作4.1安装vim4.1.1 更新软件包信息4.1.2 安装vim 4.2 换源4.2.1 备份镜像源设置文件4.2.2 编辑镜像源设置文件4.2.3 重新更新一下软件包信息 4.3 同步上海时间4.3.1 安装 tzdata4.3.2 设置 tz…

[AJAX]原生AJAX——服务端如何发出JSON格式响应,客户端如何处理接收JSON格式响应

服务端代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> &l…

IPV6使用越来越广,您会配置吗?

前面针对IPv6写过一篇文章&#xff0c;但是好多网友反映没有读懂&#xff0c;今天再给大家把内容浓缩一下&#xff0c;教给大家如何配置。 IPV6的推出主要是为了解决地址空间的不足&#xff0c;从而进一步的促进互联网的发展。IPV6地址空间大到惊人&#xff0c;有人比喻地球上…

Rust in Action笔记 第十章 进程、线程和容器

Rust的闭包也就是类似lambda表达式&#xff0c;大致的格式是|a, b| {...} &#xff0c;竖线里面的是参数&#xff0c;花括号里面的是函数逻辑&#xff1b;通过thread::spawn(|| {})产生的线程&#xff0c;括号内的参数实际上就是一个闭包&#xff0c;因为创建新的线程不需要参数…

【论文阅读】StyleganV1 算法理解

文章目录 为什么提出&#xff1f;具体是怎么做的&#xff1f;1.解耦的思想&#xff08;对应文章第四章4.Disentanglement studies&#xff09;1.1 感知路径长度&#xff08;对应4.1Perceptual path length&#xff09;1.2 线性可分离性&#xff08;对应4.2Linear separability&…

Chrome DevTools、Vue DevTools、vs和DevTools调试

目录 Elements DOM节点&#xff08;增删改&#xff09;调试 Styles DOM结构 增删属性 模拟元素的伪状态&#xff0c;方便调试 Computed Layout Event Listeners Network Application 资源列表&#xff08;可改&#xff09;本地存储Cookie、WebStorage&#xff08;loca…

人工智能学习07--pytorch22--目标检测:YOLO V3 SPP

视频链接&#xff1a; https://www.bilibili.com/video/BV1t54y1C7ra/?vd_sourceb425cf6a88c74ab02b3939ca66be1c0d yolov3 spp spp&#xff1a;空间金字塔池化 trick&#xff1a;实现的小技巧&#xff0c;方法。&#xff08; up&#xff1a;Bag of Freebies里有很多trick&…

【C++学习笔记】C++中的异常概念异常的使用注意事项异常的优缺点

异常 1 C语言传统的处理异常的方式2 C异常的概念3 异常的使用以及注意事项3.1 异常的简单使用3.2 使用异常的注意事项3.3 异常的重新抛出3.4 异常规范3.5 异常安全 4 C标准库的异常体系5 异常的优缺点6 总结 1 C语言传统的处理异常的方式 C语言传统的错误处理机制&#xff1a;…

https安全传输原理:

内容来自思学堂&#xff1a; 信息裸奔——>对称加密——>非对称加密——>非对称和对称加密——>权威第三方机构CA数字签名

C++图形开发(5):逐渐变大(小)的小球

文章目录 1.逐渐变大的小球2.逐渐变小的小球 今天所讲的逐渐变大&#xff08;小&#xff09;的小球实际上就是基于上次的缓慢下落的小球的基础上的&#xff08;下落的小球详见&#xff1a;C图形开发&#xff08;4&#xff09;&#xff1a;下落的小球&#xff09; 1.逐渐变大的…