面试基础篇——ArrayList VS LinkedList

简介: 面试基础篇——ArrayList VS LinkedList

文章目录

ArrayList 和 LinkedList 对比

1. 数据结构

2. 随机访问能力

3. 插入、删除性能

4. 内存占用

5. 测试代码


ArrayList 和 LinkedList 对比


1. 数据结构


  • ArrayList 基于数组实现,需要连续内存
  • LinkedList 基于链表实现,不需要连续内存
  • 1.png

2. 随机访问能力


ArrayList 随机访问能力快(根据下标访问)

LinkedList 随机访问能力慢(沿着链表访问)

源码

ArrayList 实现了 RandomAccess 接口

1.png

LinkedList 没有实现 RandomAccess 接口

1.png

RandomAccess 接口

1.png


代码性能对比


ArrayList 用时比 LinkedList 短

/**
 * StopWatch '': running time = 17100 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000004000  023%  ArrayList
 * 000013100  077%  LinkedList
 *
 * StopWatch '': running time = 6600 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000000700  011%  ArrayList
 * 000005900  089%  LinkedList
 *
 * StopWatch '': running time = 6200 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000000400  006%  ArrayList
 * 000005800  094%  LinkedList
 *
 * StopWatch '': running time = 8000 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000000300  004%  ArrayList
 * 000007700  096%  LinkedList
 */

注意


如果按 内容 进行查询LinkedList 和ArrayList 时间复杂度相同都是O ( n ) O(n)O(n)


3. 插入、删除性能


ArrayList:尾部插入、删除性能可以,其它部分插入、删除都会移动数据,因此性能会低

LinkedList:头尾插入、删除性能高(中间插入、删除性能低于ArrayList)


测试


头部插入性能对比(LinkedList胜)

/**
 * StopWatch '': running time = 29000 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000019000  066%  ArrayList
 * 000010000  034%  LinkedList
 *
 * StopWatch '': running time = 6200 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000004400  071%  ArrayList
 * 000001800  029%  LinkedList
 *
 * StopWatch '': running time = 4700 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000003200  068%  ArrayList
 * 000001500  032%  LinkedList
 *
 * StopWatch '': running time = 4900 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000003000  061%  ArrayList
 * 000001900  039%  LinkedList
 *
 * StopWatch '': running time = 2800 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000001900  068%  ArrayList
 * 000000900  032%  LinkedList
 */

尾部插入性能对比(不相伯仲)

/**
 * StopWatch '': running time = 35700 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000014800  041%  ArrayList
 * 000020900  059%  LinkedList
 *
 * StopWatch '': running time = 3500 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000002100  060%  ArrayList
 * 000001400  040%  LinkedList
 *
 * StopWatch '': running time = 2200 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000001200  055%  ArrayList
 * 000001000  045%  LinkedList
 *
 * StopWatch '': running time = 4100 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000002800  068%  ArrayList
 * 000001300  032%  LinkedList
 *
 * StopWatch '': running time = 2600 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000001400  054%  ArrayList
 * 000001200  046%  LinkedList
 */

中间插入性能对比(ArrayList胜)

/**
 * StopWatch '': running time = 100100 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000042800  043%  ArrayList
 * 000057300  057%  LinkedList
 *
 * StopWatch '': running time = 32500 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000007000  022%  ArrayList
 * 000025500  078%  LinkedList
 *
 * StopWatch '': running time = 32700 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000006700  020%  ArrayList
 * 000026000  080%  LinkedList
 *
 * StopWatch '': running time = 27900 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000005500  020%  ArrayList
 * 000022400  080%  LinkedList
 *
 * StopWatch '': running time = 38000 ns
 * ---------------------------------------------
 * ns         %     Task name
 * ---------------------------------------------
 * 000004500  012%  ArrayList
 * 000033500  088%  LinkedList
 */


4. 内存占用


ArrayList:占用内存少

LinkedList:占用内存多

测试

/**
 * ArrayList 总大小:[4976],array的数组长度:[1234],所有元素所占字节数::[16000]
 * LinkedList 总大小:[24080],一个Node节点的大小:[24],所有元素所占字节数:[16000]
 */


5. 测试代码


测试代码

import org.openjdk.jol.info.ClassLayout;
import org.springframework.util.StopWatch;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import static day01.sort.Utils.randomArray;
@SuppressWarnings("all")
// 需要添加VM参数 :--add-opens java.base/java.util=ALL-UNNAMED
public class ArrayListVsLinkedList {
    public static void main(String[] args) {
        int n = 1000;
        int insertIndex = n;
        for (int i = 0; i < 5; i++) {
            int[] array = randomArray(n);
            List<Integer> list1 = Arrays.stream(array).boxed().collect(Collectors.toList());
            LinkedList<Integer> list2 = new LinkedList<>(list1);
            randomAccess(list1, list2, n / 2);
//            addFirst(list1,list2);
//            addMiddle(list1, list2, n / 2);
//            addLast(list1,list2);
//            arrayListSize((ArrayList<Integer>) list1);
//            linkedListSize(list2);
        }
    }
    static void linkedListSize(LinkedList<Integer> list) {
        try {
            long size = 0;
            ClassLayout layout = ClassLayout.parseInstance(list);
//            System.out.println(layout.toPrintable());
            size += layout.instanceSize();
            Field firstField = LinkedList.class.getDeclaredField("first");
            firstField.setAccessible(true);
            Object first = firstField.get(list);
//            System.out.println(ClassLayout.parseInstance(first).toPrintable());
            long nodeSize = ClassLayout.parseInstance(first).instanceSize();
            size += (nodeSize * (list.size() + 2));
            long elementSize = ClassLayout.parseInstance(list.getFirst()).instanceSize();
            System.out.println("LinkedList 总大小:[" + size + "],一个Node节点的大小:[" + nodeSize + "],所有元素所占字节数:[" + elementSize * list.size() + "]");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    static void arrayListSize(ArrayList<Integer> list) {
        try {
            long size = 0;
            ClassLayout layout = ClassLayout.parseInstance(list);
//            System.out.println(layout.toPrintable());
            size += layout.instanceSize();
            Field elementDataField = ArrayList.class.getDeclaredField("elementData");
            elementDataField.setAccessible(true);
            Object elementData = elementDataField.get(list);
//            System.out.println(ClassLayout.parseInstance(elementData).toPrintable());
            size += ClassLayout.parseInstance(elementData).instanceSize();
            long elementSize = ClassLayout.parseInstance(list.get(0)).instanceSize();
            System.out.println("ArrayList 总大小:[" + size + "],array的数组长度:[" + length(list) + "],所有元素所占字节数::[" + elementSize * list.size() + "]");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    static void randomAccess(List<Integer> list1, LinkedList<Integer> list2, int mid) {
        StopWatch sw = new StopWatch();
        sw.start("ArrayList");
        list1.get(mid);
        sw.stop();
        sw.start("LinkedList");
        list2.get(mid);
        sw.stop();
        System.out.println(sw.prettyPrint());
    }
    private static void addMiddle(List<Integer> list1, LinkedList<Integer> list2, int mid) {
        StopWatch sw = new StopWatch();
        sw.start("ArrayList");
        list1.add(mid, 100);
        sw.stop();
        sw.start("LinkedList");
        list2.add(mid, 100);
        sw.stop();
        System.out.println(sw.prettyPrint());
    }
    private static void addFirst(List<Integer> list1, LinkedList<Integer> list2) {
        StopWatch sw = new StopWatch();
        sw.start("ArrayList");
        list1.add(0, 100);
        sw.stop();
        sw.start("LinkedList");
        list2.addFirst(100);
        sw.stop();
        System.out.println(sw.prettyPrint());
    }
    private static void addLast(List<Integer> list1, LinkedList<Integer> list2) {
        StopWatch sw = new StopWatch();
        sw.start("ArrayList");
        list1.add(100);
        sw.stop();
        sw.start("LinkedList");
        list2.add(100);
        sw.stop();
        System.out.println(sw.prettyPrint());
    }
    public static int length(ArrayList<Integer> list) {
        try {
            Field field = ArrayList.class.getDeclaredField("elementData");
            field.setAccessible(true);
            return ((Object[]) field.get(list)).length;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

工具类

import java.util.Random;
public class Utils {
    public static void swap(int[] array, int i, int j) {
        int t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
    public static void shuffle(int[] array) {
        Random rnd = new Random();
        int size = array.length;
        for (int i = size; i > 1; i--) {
            swap(array, i - 1, rnd.nextInt(i));
        }
    }
    public static int[] randomArray(int n) {
        int lastVal = 1;
        Random r = new Random();
        int[] array = new int[n];
        for (int i = 0; i < n; i++) {
            int v = lastVal + Math.max(r.nextInt(10), 1);
            array[i] = v;
            lastVal = v;
        }
        shuffle(array);
        return array;
    }
    public static int[] evenArray(int n) {
        int[] array = new int[n];
        for (int i = 0; i < n; i++) {
            array[i] = i * 2;
        }
        return array;
    }
    public static int[] sixteenArray(int n) {
        int[] array = new int[n];
        for (int i = 0; i < n; i++) {
            array[i] = i * 16;
        }
        return array;
    }
    public static int[] lowSameArray(int n) {
        int[] array = new int[n];
        Random r = new Random();
        for (int i = 0; i < n; i++) {
            array[i] = r.nextInt() & 0x7FFF0002;
        }
        return array;
    }
}


代码说明


day01.list.ArrayListVsLinkedList#randomAccess 对比随机访问性能

day01.list.ArrayListVsLinkedList#addMiddle 对比向中间插入性能

day01.list.ArrayListVsLinkedList#addFirst 对比头部插入性能

day01.list.ArrayListVsLinkedList#addLast 对比尾部插入性能

day01.list.ArrayListVsLinkedList#linkedListSize 打印一个 LinkedList 占用内存

day01.list.ArrayListVsLinkedList#arrayListSize 打印一个 ArrayList 占用内存

相关文章
|
2月前
|
Java
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
2月前
|
存储 Java 索引
【Java集合类面试二十四】、ArrayList和LinkedList有什么区别?
ArrayList基于动态数组实现,支持快速随机访问;LinkedList基于双向链表实现,插入和删除操作更高效,但占用更多内存。
|
3月前
|
存储 安全 Java
面试官没想到一个ArrayList,我都能跟他扯半小时
面试官:List集合都知道哪些对象?作为四大集合之一的List,在业务开发中我们比较常见的是以下 3 种:ArrayList、Vector、LinkedList,业务开发我们接触最多就是容器类库了,容器类库可以说是面向对象语言最重要的类库。大家看看在工作里你比较熟悉的是哪个?这篇文章南哥打算专注于List集合,后面四大集合之Map、Queue、Set后续再来填坑,比心心♥。
127 2
面试官没想到一个ArrayList,我都能跟他扯半小时
|
2月前
|
Java 编译器 开发工具
JDK vs JRE:面试大揭秘,一文让你彻底解锁Java开发和运行的秘密!
【8月更文挑战第24天】JDK(Java Development Kit)与JRE(Java Runtime Environment)是Java环境中两个核心概念。JDK作为开发工具包,不仅包含JRE,还提供编译器等开发工具,支持Java程序的开发与编译;而JRE仅包含运行Java程序所需的组件如JVM和核心类库。一个简单的&quot;Hello, World!&quot;示例展示了两者用途:需借助JDK编译程序,再利用JRE或JDK中的运行环境执行。因此,开发者应基于实际需求选择安装JDK或JRE。
41 0
|
2月前
|
前端开发 应用服务中间件 API
"揭秘!面试官必问:你是如何巧妙绕过跨域难题的?前端代理VS服务器端CORS,哪个才是你的秘密武器?"
【8月更文挑战第21天】在软件开发中,尤其前后端分离架构下,跨域资源共享(CORS)是常见的挑战。主要解决方案有两种:一是服务器端配置CORS策略,通过设置响应头控制跨域访问权限,无需改动前端代码,增强安全性;二是前端代理转发,如使用Nginx或Webpack DevServer在开发环境中转发请求绕过同源策略,简化开发流程但不适用于生产环境。生产环境下应采用服务器端CORS策略以确保安全稳定。
34 0
|
2月前
|
存储 SQL 搜索推荐
一天十道Java面试题----第一天(面向对象-------》ArrayList和LinkedList)
这篇文章是关于Java面试的笔记,涵盖了面向对象、JDK/JRE/JVM的区别、`==`和`equals`、`final`关键字、`String`、`StringBuffer`和`StringBuilder`的区别、重载与重写、接口与抽象类、`List`与`Set`、`hashcode`与`equals`以及`ArrayList`和`LinkedList`的对比等十个主题。
|
3月前
|
存储 安全 Java
Android面试题之ArrayList源码详解
ArrayList是Java中基于数组实现的列表,提供O(1)的索引访问,但插入和删除操作平均时间复杂度为O(n)。默认容量为10,当需要时会通过System.arraycopy扩容。允许存储null,非线程安全。面试常问:List是接口,ArrayList是其实现之一,推荐使用List接口编程以实现更好的灵活性。更多详情见[ArrayList源码](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/ArrayList.java#ArrayList.Node)。
26 2
|
3月前
|
设计模式 并行计算 安全
Java面试题: 如何使用装饰器模式来增强ConcurrentHashMap的功能?在什么情况下应该使用CopyOnWriteArrayList而不是ArrayList?
Java面试题: 如何使用装饰器模式来增强ConcurrentHashMap的功能?在什么情况下应该使用CopyOnWriteArrayList而不是ArrayList?
27 0
|
4月前
|
开发框架 Java C++
SpringIOC第二课,@Bean用法,DI详解,常见面试题Autowired VS Resource
SpringIOC第二课,@Bean用法,DI详解,常见面试题Autowired VS Resource
|
4月前
|
存储 安全 Java
《ArrayList & HashMap 源码类基础面试题》面试官们最喜欢问的ArrayList & HashMap源码类初级问,你都会了?
《ArrayList & HashMap 源码类基础面试题》面试官们最喜欢问的ArrayList & HashMap源码类初级问,你都会了?
32 0
下一篇
无影云桌面