基础篇——ArrayList VS LinkedList

ArrayList 和 LinkedList 对比

1. 数据结构

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

在这里插入图片描述

2. 随机访问能力

  • ArrayList 随机访问能力快(根据下标访问)
  • LinkedList 随机访问能力慢(沿着链表访问)

源码

ArrayList 实现了 RandomAccess 接口

在这里插入图片描述

LinkedList 没有实现 RandomAccess 接口

在这里插入图片描述

RandomAccess 接口

在这里插入图片描述
代码性能对比

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 占用内存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值