0

0

ArrayList与LinkedList的Big-O复杂度分析

霞舞

霞舞

发布时间:2025-12-01 18:09:10

|

1000人浏览过

|

来源于php中文网

原创

arraylist与linkedlist的big-o复杂度分析

本文深入探讨了Java中ArrayList和LinkedList两种常用数据结构在核心操作上的时间复杂度(Big-O表示法)。我们将详细分析它们在随机访问(遍历到列表中间)和中间位置修改(插入/删除)操作上的性能差异,解释其底层实现原理,并提供选择建议。理解这些复杂度对于优化代码性能和选择合适的数据结构至关重要。

软件开发中,选择合适的数据结构是构建高效应用程序的关键。Java集合框架提供了多种列表实现,其中ArrayList和LinkedList是两种最常用且功能互补的动态列表。理解它们在不同操作下的时间复杂度(Big-O表示法)对于优化程序性能至关重要。Big-O复杂度描述了算法的运行时间或空间需求如何随着输入数据量的增加而增长,它提供了一种衡量算法效率的抽象方式。

ArrayList的性能特性

ArrayList基于动态数组实现,其底层是一个可变大小的数组。这一特性决定了它在访问和修改操作上的独特性能表现。

1. 随机访问(遍历到列表中间)

时间复杂度:O(1)

ArrayList支持高效的随机访问。这意味着,无论列表有多长,获取任何位置的元素所需的时间都是常数级别的,与列表大小无关。例如,从一个包含五百万个元素的ArrayList中获取第两百五十万个元素,其耗时与从一个包含十个元素的ArrayList中获取第五个元素大致相同。

原因分析: 由于ArrayList的底层是数组,元素在内存中是连续存储的。给定一个索引,系统可以直接通过内存地址计算快速定位到目标元素,无需遍历。

示例代码:

import java.util.ArrayList;
import java.util.List;

public class ArrayListAccessExample {
    public static void main(String[] args) {
        List arrayList = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            arrayList.add("Element " + i);
        }

        // 随机访问中间元素
        long startTime = System.nanoTime();
        String middleElement = arrayList.get(arrayList.size() / 2);
        long endTime = System.nanoTime();
        System.out.println("ArrayList随机访问中间元素: " + middleElement);
        System.out.println("耗时: " + (endTime - startTime) + " 纳秒");
    }
}

2. 中间位置修改(插入与删除)

时间复杂度:O(n)

用Apache Spark进行大数据处理
用Apache Spark进行大数据处理

本文档主要讲述的是用Apache Spark进行大数据处理——第一部分:入门介绍;Apache Spark是一个围绕速度、易用性和复杂分析构建的大数据处理框架。最初在2009年由加州大学伯克利分校的AMPLab开发,并于2010年成为Apache的开源项目之一。 在这个Apache Spark文章系列的第一部分中,我们将了解到什么是Spark,它与典型的MapReduce解决方案的比较以及它如何为大数据处理提供了一套完整的工具。希望本文档会给有需要的朋友带来帮助;感

下载

在ArrayList的中间位置插入或删除元素,其操作成本较高,与列表大小成正比。

原因分析: 当在ArrayList的中间位置插入一个元素时,为了保持数组的连续性,所有位于插入点之后的元素都需要向后移动一位。同样,当删除一个元素时,其后的所有元素都需要向前移动一位以填补空缺。元素移动的数量随着列表大小的增加而增加。

示例代码:

import java.util.ArrayList;
import java.util.List;

public class ArrayListModificationExample {
    public static void main(String[] args) {
        List arrayList = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            arrayList.add("Element " + i);
        }

        int middleIndex = arrayList.size() / 2;

        // 在中间位置插入元素
        long startTimeInsert = System.nanoTime();
        arrayList.add(middleIndex, "New Middle Element");
        long endTimeInsert = System.nanoTime();
        System.out.println("ArrayList中间插入耗时: " + (endTimeInsert - startTimeInsert) + " 纳秒");

        // 在中间位置删除元素
        long startTimeDelete = System.nanoTime();
        arrayList.remove(middleIndex);
        long endTimeDelete = System.nanoTime();
        System.out.println("ArrayList中间删除耗时: " + (endTimeDelete - startTimeDelete) + " 纳秒");
    }
}

注意事项: 如果只是更新ArrayList中某个已知索引位置的元素值(而非插入或删除),其操作复杂度为O(1),因为这仅仅是简单地覆盖了该内存位置的值,不涉及元素移动。

LinkedList的性能特性

LinkedList基于双向链表实现,每个元素(节点)都包含数据以及指向前一个和后一个节点的引用。这种链式结构使其在访问和修改操作上与ArrayList截然不同。

1. 顺序访问(遍历到列表中间)

时间复杂度:O(n)

LinkedList不支持随机访问。要访问列表中的某个特定元素,必须从列表的头部或尾部开始,逐个节点地遍历,直到找到目标元素。因此,访问中间元素所需的时间与列表大小成正比。

原因分析: 由于LinkedList的元素在内存中不一定是连续存储的,它只能通过节点之间的指针进行导航。无法像数组那样通过索引直接计算地址。

示例代码:

import java.util.LinkedList;
import java.util.List;

public class LinkedListAccessExample {
    public static void main(String[] args) {
        List linkedList = new LinkedList<>();
        for (int i = 0; i < 1000000; i++) {
            linkedList.add("Element " + i);
        }

        // 顺序访问中间元素
        long startTime = System.nanoTime();
        String middleElement = linkedList.get(linkedList.size() / 2); // get方法会触发O(n)遍历
        long endTime = System.nanoTime();
        System.out.println("LinkedList顺序访问中间元素: " + middleElement);
        System.out.println("耗时: " + (endTime - startTime) + " 纳秒");
    }
}

2. 中间位置修改(插入与删除)

时间复杂度:O(1) (在已知目标节点后)

在LinkedList的中间位置进行插入或删除操作,一旦定位到目标节点,实际的修改操作本身非常高效,是常数时间复杂度。

原因分析: 插入一个新节点时,只需调整新节点及其前后节点的指针即可。删除一个节点时,也只需调整其前后节点的指针,使其互相指向,然后被删除的节点就会被垃圾回收。这些指针操作都是O(1)。

关键点: 虽然插入和删除操作本身是O(1),但前提是必须先遍历到目标位置。因此,如果需要从头开始查找并定位到中间位置,则整个操作(包括遍历)的复杂度仍然是O(n)

伪代码示例(假设已定位到目标节点currentNode):

// 插入新节点
newNode.next = currentNode.next;
newNode.prev = currentNode;
currentNode.next.prev = newNode;
currentNode.next = newNode;

// 删除节点
currentNode.prev.next = currentNode.next;
currentNode.next.prev = currentNode.prev;
// currentNode失去引用,等待垃圾回收

总结与选择建议

下表总结了ArrayList和LinkedList在关键操作上的Big-O复杂度:

操作 ArrayList LinkedList
随机访问 (get(index)) O(1) O(n)
中间插入 (add(index, E)) O(n) O(n) (包含遍历)
中间删除 (remove(index)) O(n) O(n) (包含遍历)
头部插入/删除 O(n) O(1)
尾部插入/删除 O(1) (均摊) O(1)

何时选择ArrayList:

  • 需要频繁进行随机访问(get(index)操作)。
  • 列表主要用于存储和读取数据,较少进行中间位置的插入或删除。
  • 内存占用有一定要求(相对LinkedList,ArrayList的每个元素开销更小,因为它不存储额外的前后指针)。

何时选择LinkedList:

  • 需要频繁在列表的头部或尾部进行插入或删除操作。
  • 需要频繁在列表的中间位置进行插入或删除操作,并且通常能够快速定位到目标位置(例如,通过迭代器遍历时进行操作)。
  • 对内存使用效率要求不高,或者列表长度不确定且变化频繁。

在实际应用中,开发者应根据具体的使用场景和操作模式来权衡选择ArrayList或LinkedList,以实现最佳的性能表现。例如,如果一个应用程序需要频繁地在列表两端添加或移除元素(如实现队列或),LinkedList通常是更好的选择。而如果应用程序需要根据索引快速查找和读取元素,ArrayList则更为高效。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

832

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

738

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

734

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.5万人学习

C# 教程
C# 教程

共94课时 | 6.8万人学习

Java 教程
Java 教程

共578课时 | 46.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号