面试基础篇——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 占用内存

相关文章
|
7月前
|
存储 Java 索引
【面试题精讲】ArrayList 和 Array(数组)的区别?
【面试题精讲】ArrayList 和 Array(数组)的区别?
|
7月前
|
Java
【面试题精讲】ArrayList 插入和删除元素的时间复杂度
【面试题精讲】ArrayList 插入和删除元素的时间复杂度
|
7月前
|
存储 安全 Java
【面试题精讲】ArrayList 和 Vector 的区别?
【面试题精讲】ArrayList 和 Vector 的区别?
|
7月前
|
存储 缓存 Java
每日一道面试题之LinkedList VS ArrayList~
每日一道面试题之LinkedList VS ArrayList~
|
18天前
|
Java
[Java 面试题] ArrayList篇
[Java 面试题] ArrayList篇
|
7月前
|
存储 Java 索引
每日一道面试题之ArrayList 和 LinkedList 的区别是什么?
每日一道面试题之ArrayList 和 LinkedList 的区别是什么?
|
4月前
|
存储 算法 关系型数据库
【面试普通人VS高手系列】b树和b+树的理解
【面试普通人VS高手系列】b树和b+树的理解
|
4月前
面试题之:ArrayList和LinkedList有哪些区别
面试题之:ArrayList和LinkedList有哪些区别
|
7月前
|
存储 Java
【面试题精讲】ArrayList 可以添加 null 值吗
【面试题精讲】ArrayList 可以添加 null 值吗
|
7月前
|
Cloud Native 程序员 Go
硬技能VS软技能:面试中哪个更重要?
硬技能VS软技能:面试中哪个更重要?
80 0