ArrayList 和LinkedList的区别比较

news2025/1/2 18:35:41

前言

‌ArrayList和LinkedList的主要区别在于它们的底层数据结构、性能特点以及适用场景。‌ArrayList和LinkedList从名字分析,他们一个是Array(动态数组)的数据结构,一个是Linked(链表)的数据结构,此外,他们两个都是对List接口的实现。前者是数组队列,相当于动态数组;后者为双向链表结构,也可当作堆栈、队列、双端队列。

一、底层数据结构

ArrayList‌:基于动态数组实现。它维护一个Object类型的数组来存储元素,可以根据需要自动扩展容量。当元素数量超过当前容量时,ArrayList会进行扩容操作,通常是将现有元素复制到一个新的更大数组中‌。 

LinkedList‌:基于双向链表实现。每个节点包含存储的元素、指向前一个节点的引用和指向下一个节点的引用。LinkedList不需要预先分配固定大小的空间,可以在链表的头部或尾部灵活地添加或删除元素‌。

二、性能特点

2‌.1 查询性能‌:

ArrayList‌:通过索引直接访问元素,查询速度非常快,时间复杂度为O(1)。适合需要频繁访问特定‌位置数据的场景‌。

LinkedList‌:由于需要遍历链表来找到指定索引的元素,查询速度较慢,时间复杂度为O(n)‌。

2.2 添加和删除性能‌:

‌ArrayList‌:在列表中间插入或删除元素时,需要移动后续的所有元素,时间复杂度为O(n)。因此,在列表中间进行添加或删除操作时,LinkedList通常更快‌。

LinkedList‌:在头部或尾部添加或删除元素时,只需更改指针引用,时间复杂度为O(1),因此在这些位置进行操作时更快‌。

三、空间和耗时效率对比

从利用效率来看,ArrayList自由性较低,因为它需要手动的设置固定大小的变化,但是他的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的数据量的变化而变化,但是他不便于使用。

ArrayList主要的空间开销在于需要在IList列表预留一定空间;而LinkedList主要空间开销在于需要存储节点信息以及结点指针信息。

ArrayList想要在指定位置插入或删除元素时,主要耗时的是 System.arraycopy 动作,会移动 index 后面所有的元素;LinkedList 主耗时的是要先通过 for 循环找到 index,然后直接插入或删除。这就导致了两者并非一定谁快谁慢。 主要有两个因素决定他们的效率,插入的数据量和插入的位置。

LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。

四、ArrayList 扩容问题

ArrayList 使用一个内置的数组来存储元素,这个数组的起始容量是 10,当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的 ArrayList 对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。

五、ArrayList随机访问比LinkedList快的原因

ArrayList从原理上就是数据结构中的数组,也就是内存中的一片空间,这意味着,当我get(index)的时候,我可以根据数组的首地址+偏移量,直接计算出我想访问的第index元素在内存中的位置;而LinkedList可以简单理解为数据结构中的链表,在内存中开辟的不是一段连续的空间,而是每个元素有一个元素和下一个元素地址这样的内存结构,当get(index)时,只能从首元素开始,依次获取下一个元素的地址。上面已经说过,用时间复杂度来表示的话,ArrayList的get(index)是O(1),而LinkedList是O(n)。

我们编写代码对比测试,说明两者的性能:

1. 定义抽象类,作为List接口的测试,并定义有测试方法

//定义内部抽象类,作为List测试。
private abstract static class Tester {
            

        String name;
        int size;

        Tester(String name, int size) {
            this.name = name;
            this.size = size;
        }

        //定义抽象方法
        abstract void test(List a);
    }

2. 定义一个测试的数组,分别存储获取、遍历、插入和删除的方法

private static final int LOOP_COUNTS = 1000;

private static Tester[] tests = {
            //一个测试数组,存储get(随机取)、iteration(顺序遍历)、insert(中间插入)、remove(随机删除)

            new Tester("get", 500) {
                void test(List a) {
                    for (int i = 0; i < LOOP_COUNTS; i++) {
                        for (int j = 0; j < a.size(); j++) {
                            a.get(j);
                        }
                    }
                }
            },
            new Tester("iteration", 500) {
                void test(List a) {
                    for (int i = 0; i < LOOP_COUNTS; i++) {
                        Iterator it = a.iterator();
                        while (it.hasNext()) {
                            it.next();
                        }
                    }
                }
            },
            new Tester("insert", 2000) {
                void test(List a) {
                    int half = a.size() / 2;
                    String s = "test";
                    ListIterator it = a.listIterator(half);
                    for (int i = 0; i < size * 10; i++) {
                        it.add(s);
                    }
                }
            },
            new Tester("remove", 5000) {
                void test(List a) {
                    ListIterator it = a.listIterator(3);
                    while (it.hasNext()) {
                        it.next();
                        it.remove();
                    }
                }
            }
    };

 3. 编写测试方法

public static void test(List a) {
        //输出测试的类名称
        System.out.println("Testing for --" + a.getClass().getName());
        for (int i = 0; i < tests.length; i++) {
            fill(a, tests[i].size);//填充空集合
            System.out.print(tests[i].name);
            long t1 = System.currentTimeMillis();
            tests[i].test(a);//进行测试
            long t2 = System.currentTimeMillis();
            System.out.print("花费时间:" + (t2 - t1) + " ms ,");
        }
    }


public static Collection fill(Collection c, int size) {
        for (int i = 0; i < size; i++) {
            c.add(Integer.toString(i));
        }
        return c;
    }

4. 调用ArrayList和LinkedList的方法

public static void main(String[] args) {
        test(new ArrayList());
        System.out.println();
        test(new LinkedList());
    }

 5. 运行结果

六、适用场景

‌ArrayList‌:适合需要频繁访问特定位置数据的场景,如排行榜、购物车列表等。由于扩容机制的存在,建议在创建时指定初始容量以减少扩容次数‌。

‌LinkedList‌:适合需要频繁在列表开头、中间或末尾进行添加和删除操作的场景。由于其链表结构,插入和删除操作更为高效‌。

总之, 它们的适用场景:Array数组,查找快,插入删除慢。 适用于频繁查找和修改的场景。Linked链表,插入删除快,查找修改慢。适用于频繁添加和删除的场景。

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

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

相关文章

MySQL--》如何在SQL中巧妙运用函数与约束,优化数据处理与验证?

目录 函数使用 字符串函数 数值函数 日期函数 流程函数 约束 外键约束 约束规则 函数使用 函数是指一段可以直接被另一段程序调用的程序或代码&#xff0c;在mysql当中有许多常见的内置函数&#xff0c;接下来开始对这些内置函数及其作用进行简单的讲解和使用&#xf…

一文大白话讲清楚CSS盒子模型和块级格式化上下文(BFC)

一文大白话讲清楚CSS盒子模型和块级格式化上下文&#xff08;BFC&#xff09; 1.啥是个CSS盒子 鞋盒你家总有吧&#xff0c;方方正正&#xff0c;有长度有高度。css盒子跟这个八九不离十当我们编写html页面时&#xff0c;写了很多的元素&#xff0c;比如"div",&quo…

Docker 快速搭建 GBase 8s数据库服务

1.查看Gbase 8s镜像版本 可以去到docker hub网站搜索&#xff1a;gbase8s liaosnet/gbase8s如果无法访问到该网站&#xff0c;可以通过docker search搜索 docker search gbase8s2.拉取Gbase 8s镜像 以下演示的版本是目前官网最新版本Gbase8sV8.8_3.5.1 docker pull liaosn…

密钥登录服务器

1. 生成 SSH 密钥对 如果您还没有生成密钥对&#xff0c;可以使用以下命令生成&#xff1a; ssh-keygen 在 root 用户的家目录中生成了一个 .ssh 的隐藏目录&#xff0c;内含两个密钥文件&#xff1a;id_rsa 为私钥&#xff0c;id_rsa.pub 为公钥。 在提示时&#xff0c;您可…

王佩丰24节Excel学习笔记——第二十讲:图表基础

【以 Excel2010 系列学习&#xff0c;用 Office LTSC 专业增强版 2021 实践】 【本章技巧】 课件图片有问题&#xff0c;不能随隐藏熟悉各个图表小部件的功能&#xff0c;需要修改都是选中右键进行更改。 一、认识图表中的元素 图表标题&#xff1a;主坐标&#xff08;横坐标&…

华为交换机配置本地端口流量镜像

端口镜像&#xff08;Port Mirroring&#xff09;是网络监控的一种重要技术&#xff0c;通过复制流经特定端口的报文&#xff0c;并将其传送到指定的观察端口&#xff0c;以便对网络流量进行分析和监控。下面将详细介绍如何在华为交换机上配置本地端口镜像&#xff0c;以N:1镜像…

IDEA设置作者信息 日期等

file -> setting 或 ctrl alt s找到如下 然后添加注释即可 可以直接编辑5处的文字&#xff0c;在 author 后放自己的名字即可 /*** author 你的名字* date ${DATE} ${TIME})*/当然 整体不止这些 &#xff0c;看下面的描述中&#xff0c;还有很多其他选项 也可以 4 这…

【stm32can】

can时钟 can波特率计算&#xff08;位同步内容&#xff09; ss是固定的1tq&#xff0c; pts&#xff0c;pbs1&#xff0c;pbs2是用户设定值 同步时间段的理解有误&#xff1f; 原文出处 数据帧 遥控帧

【论文笔记】Contrastive Learning for Sign Language Recognition and Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Contrastive Learning for…

springboot514基于SpringBoot的家电销售展示平台(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装家电销售展示平台软件来发挥其高效地信息处理的作用&#x…

【探花交友】day03—MongoDB基础

目录 课程介绍 1、通用设置 1.1 需求分析 1.2 查询通用设置 1.2 陌生人问题 1.3 通知设置 1.4 黑名单管理 2、MongoDB简介 1.1、MongoDB简介 1.2、MongoDB的特点 1.3 数据类型 3、MongoDB入门 2.1、数据库以及表的操作 2.2、新增数据 2.3、更新数据 2.4、删除数…

uniapp不能直接修改props的数据原理浅析

uniapp不能直接修改props的数据 Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the props value. Prop being mutated: "expectDeliveryAt" 避…

大数据存储Nosql

大数据存储Nosql复习篇 一、理论题、论述题 第1章 绪论 1、NoSQL数据库和关系数据库在设计目标上有何主要区别&#xff1f; (1)关系数据库 优势&#xff1a;以完善的关系代数理论作为基础&#xff0c;具有数据模型、完整性约束和事务的强一致性等特点&#xff0c;借助索引机…

ONLYOFFICE 协作空间 3.0 新功能详解

ONLYOFFICE 协作空间 3.0 新功能详解 书接上文&#xff1a; ONLYOFFICE 协作空间 3.0 发布: 新增虚拟数据房间、用户类型、OAuth 2.0 等更新 简单的介绍了一下 ONLYOFFICE 协作空间 3.0 的新功能&#xff0c;今天我们详细介绍一下这些新功能。 关于 ONLYOFFICE 协作空间 O…

ASP.NET |日常开发中常见问题归纳讲解

ASP.NET &#xff5c;日常开发中常见问题归纳讲解 前言一、性能问题1.1 数据库访问性能1.2 视图状态&#xff08;在ASP.NET Web Forms 中&#xff09; 二、安全问题2.1 SQL 注入2.2 跨站脚本攻击&#xff08;XSS&#xff09; 三、状态管理问题3.1 会话状态&#xff08;Session …

ADC(三):注入组的使用

有关ADC的基础知识请参考标准库入门教程 ADC&#xff08;三&#xff09;&#xff1a;注入组的使用 1、规则组软件触发注入组自动注入2、规则组外部触发注入组自动注入3、规则组软件触发注入组外部触发&#xff08;TIM2_CC1&#xff09;4、规则组软件触发注入组外部触发&#xf…

Debian 12 安装配置 fail2ban 保护 SSH 访问

背景介绍 双十一的时候薅羊毛租了台腾讯云的虚机, 是真便宜, 只是没想到才跑了一个月, 系统里面就收集到了巨多的 SSH 恶意登录失败记录. 只能说, 互联网真的是太不安全了. 之前有用过 fail2ban 在 CentOS 7 上面做过防护, 不过那已经是好久好久之前的故事了, 好多方法已经不…

基于Spring Boot + Vue3实现的在线商品竞拍管理系统源码+文档

前言 基于Spring Boot Vue3实现的在线商品竞拍管理系统是一种现代化的前后端分离架构的应用程序&#xff0c;它结合了Java后端框架Spring Boot和JavaScript前端框架Vue.js的最新版本&#xff08;Vue 3&#xff09;。该系统允许用户在线参与商品竞拍&#xff0c;并提供管理后台…

编译openssl遇到错误Parse errors: No plan found in TAP output的解决方法

在编译openssl时 tar -zxvf openssl-1.1.1p.tar.gz cd openssl-1.1.1p ./config --prefix/usr --openssldir/etc/ssl --shared zlib make make test 遇到错误 Parse errors: No plan found in TAP output 解决方法&#xff1a; yum install perl-Test-Simple

20241130 RocketMQ本机安装与SpringBoot整合

目录 一、RocketMQ简介 ???1.1、核心概念 ???1.2、应用场景 ???1.3、架构设计 2、RocketMQ Server安装 3、RocketMQ可视化控制台安装与使用 4、SpringBoot整合RocketMQ实现消息发送和接收? ? ? ? ? 4.1、添加maven依赖 ???4.2、yaml配置 ???4.3、…