ArrayList与LinkedList比较

1.实现方式

ArrayList内部结构为数组,定义如下:

/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

LinkedList内部结构为双向循环链表,定义如下:

/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first; /**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last; // Node节点定义
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev; Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

2.使用场景

ArrayList适用于随机访问

LinkedList适用于于随机位置增加、删除

3.插入删除

ArrayList在插入删除时需要移动index后面的所有元素

LinkedList在插入删除时只需遍历,不需要移动元素

4.随机访问

ArrayList支持通过下标访问元素,效率高

LinkedList每次访问通过头尾遍历,效率低

5.空间占用

ArrayList因为有扩容操作,在尾部预留有额外空间,每次扩容为150%,造成一定的空间浪费(初始大小为10)

LinkedList虽然没有浪费空间,但是每个元素都存储在Node对象中,占用空间比ArrayList大

6.遍历方式

ArrayList可以使用for循环,forEach,iterator

LinkedList一般使用forEach,iterator

7.继承接口

ArrayList继承了RandomAccess接口,RandomAccess是一个标记接口,用于标明实现该接口的List支持快速随机访问,主要目的是使算法能够在随机和顺序访问的List中性能更加高效(在Collections二分查找时)。如果集合类实现了RandomAccess,则尽量用for循环来遍历,没有实现则用Iterator进行遍历。

LinkedList继承了Deque接口,便于实现栈和队列

8.性能分析

操作 ArrayList LinkedList
get(index) O(1) O(n)
add() O(1) O(1)
add(index) O(n) O(n)
remove() O(n) O(n)

可以发现,LinkedList的add(index),和remove()的复杂度也是O(n),与ArrayList并没有差别,这是因为在增删之前需要先得到增删元素的位置,然后才能进行增删,然而LinkedList只能通过遍历来得到位置,因此复杂度为O(n),并不是O(1)。

  1. 末端插入,虽然二者都是O(1),但是LinkedList每次插入都要new一个对象。因此,当数据量小时,LinkedList速度快,随着数据量的增加,ArrayList速度更快。
  2. 随机插入

    LinkedList对于插入有一个优化:当插入位置小于(size/2)时从头遍历,当插入位置大于(size/2)时,从尾遍历。

    2.1 在前半段随机插入,一般来说,此时的LinkedList效率高于ArrayList。

    2.2 在后半段随机插入,此时很难判断,因为在后半段,ArrayList的copy()消耗减少,而对于LinkedList来说效率不变,因此二者的性能相差不大。

代码验证,使用一个大小为1000000的List,向其中插入500000条数据,验证在不同插入位置List的性能

耗时 ArrayList LinkedList
插入位置:末尾 0.034s 0.034s
插入位置:999999 17.166s 447.135s
插入位置:500001 120.862s 1024.761s
插入位置:1 307.608s 0.045s
插入位置:0 381.185s 0.039s
插入位置:250000 240.943s 621.257s
插入位置:0,2,4,6... 63.837s 692.319s

总结:只有当频繁在List前端位置进行增删操作,才选用LinkedList。一般情况,都选用ArrayList。

测试代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; /**
* Test
*/
public class Test { //在末端插入
public static void addTest(List list, int num) {
long startTime = System.currentTimeMillis();
for(int i=0; i<num; i++) {
int a = (int) Math.round(Math.random()*num);
list.add(a);
}
long endTime = System.currentTimeMillis();
System.out.println("addTime: " + (endTime-startTime)/1000.0 + "s size:" + list.size());
} // 在指定位置插入
public static void insertTest(List list, int num, int index) { long totalTime=0;
long startTime=0;
long endTime=0; startTime = System.currentTimeMillis();
for(int i=0; i<num; i++) {
int a = (int) Math.round(Math.random()*num); startTime = System.currentTimeMillis();
list.add(index, a);
endTime = System.currentTimeMillis();
totalTime += (endTime-startTime);
}
System.out.println("insertTime: " + (totalTime)/1000.0 + "s size:" + list.size());
} // 间隔插入
public static void insertTest(List list, int num) { long totalTime=0;
long startTime=0;
long endTime=0; for(int i=0; i<num; i++) {
int a = (int) Math.round(Math.random()*num); startTime = System.currentTimeMillis();
list.add(2*i, a);
endTime = System.currentTimeMillis();
list.remove(2*i);
totalTime += (endTime-startTime);
} System.out.println("insertTime: " + (totalTime)/1000.0 + "s size:" + list.size());
} public static void main(String[] args) { ArrayList<Integer> array = new ArrayList<Integer>();
LinkedList<Integer> link = new LinkedList<Integer>();
int num = 1000000;
int index = 250000; //Test.addTest(link, num);
//Test.addTest(link, 500000);
//Test.insertTest(link, 500000, index);
//Test.insertTest(link, 500000); Test.addTest(array, num);
//Test.addTest(array, 500000);
//Test.insertTest(array, 500000, index);
Test.insertTest(array, 500000); }
}

ArrayList与LinkedList比较的更多相关文章

  1. 深入理解java中的ArrayList和LinkedList

    杂谈最基本数据结构--"线性表": 表结构是一种最基本的数据结构,最常见的实现是数组,几乎在每个程序每一种开发语言中都提供了数组这个顺序存储的线性表结构实现. 什么是线性表? 由0 ...

  2. ArrayList,Vector,LinkedList

    在java.util包中定义的类集框架其核心的组成接口有如下:·Collection接口:负责保存单值的最大父接口 |-List子接口:允许保存重复元素,数据的保存顺序就是数据的增加顺序: |-Set ...

  3. Java数据结构之表的增删对比---ArrayList与LinkedList之一

    一.Java_Collections表的实现 与c不同Java已经实现并封装了现成的表数据结构,顺序表以及链表. 1.ArrayList是基于数组的实现,因此具有的特点是:1.有索引值方便查找,对于g ...

  4. C++模拟实现JDK中的ArrayList和LinkedList

    Java实现ArrayList和LinkedList的方式采用的是数组和链表.以下是用C++代码的模拟: 声明Collection接口: #ifndef COLLECTION_H_ #define C ...

  5. ArrayList与LinkedList用法与区别

    1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构.  2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedLis ...

  6. ArrayList vs LinkedList vs Vector

    List概览 List,正如它的名字,表明其是有顺序的.当讨论List的时候,最好拿它跟Set作比较,Set中的元素是无序且唯一:下面是一张类层次结构图,从这张图中,我们可以大致了解java集合类的整 ...

  7. ArrayList 和 LinkedList 的区别

    1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构.2.对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动 ...

  8. ArrayList和LinkedList的几种循环遍历方式及性能对比分析(转)

    主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论. 通过本文你可以 ...

  9. ArrayList和LinkedList的几种循环遍历方式及性能对比分析

    最新最准确内容建议直接访问原文:ArrayList和LinkedList的几种循环遍历方式及性能对比分析 主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性 ...

  10. 集合中list、ArrayList、LinkedList、Vector的区别、Collection接口的共性方法以及数据结构的总结

    List (链表|线性表) 特点: 接口,可存放重复元素,元素存取是有序的,允许在指定位置插入元素,并通过索引来访问元素 1.创建一个用指定可视行数初始化的新滚动列表.默认情况下,不允许进行多项选择. ...

随机推荐

  1. 工厂设计模式灵魂拷问-Java实现

    show me the code and take to me,做的出来更要说的明白 GitHub项目JavaHouse同步收录 喜欢就点个赞呗! 你的支持是我分享的动力! 引入 我们经常听到工厂模式 ...

  2. 基于 Apache APISIX 的下一代微服务架构

    2019 年 12 月 14 日,又拍云联合 Apache APISIX 社区举办 API 网关与高性能服务最佳实践丨Open Talk 广州站活动,Apache APISIX PPMC 温铭做了题为 ...

  3. cocos2dx Quaternion 四元数(1/2)

    这篇文章只是我学完四元数之后的一些理解,其实是对别人理解的理解,有些地方我理解但是没有写下来,如果真的想深入的学习四元数,建议从学习复数开始. 这个知识点需要几何想象的天赋和学习的耐心,缺一不可,慢慢 ...

  4. $Noip2012\ Luogu1081$ 开车旅行 倍增优化$ DP$

    Luogu Description Sol 1.发现对于每个城市,小A和小B的选择是固定的,可以预处理出来,分别记为ga[],gb[] 2.并且,只要知道了出发城市和出发天数,那么当前城市和小A,小B ...

  5. 大数据(5)---分布式任务资源调度Yarn

    前面也说到过的Yarn是hadoop体系中的资源调度平台.所以在整个hadoop的包里面自然也是有它的.这里我们就简单介绍下,并配置搭建yarn集群. 首先来说Yarn中有两大核心角色Resource ...

  6. 【一起学源码-微服务】Nexflix Eureka 源码五:EurekaClient启动要经历哪些艰难险阻?

    前言 在源码分析三.四都有提及到EurekaClient启动的一些过程.因为EurekaServer在集群模式下 自己本身就是一个client,所以之前初始化eurekaServerContext就有 ...

  7. C# 添加文本、图片到PDF文档(基于Spire.Cloud.PDF.SDK)

    Spire.Cloud.PDF.SDK提供了接口PdfTextApi及PdfImagesApi用于添加文本和图片到PDF文档,添加文本时,可格式化文本样式,包括文本字体类型.字号.字体样式.文本颜色. ...

  8. 1084 外观数列 (20 分)C语言

    外观数列是指具有以下特点的整数序列: d, d1, d111, d113, d11231, d112213111, ... 它从不等于 1 的数字 d 开始,序列的第 n+1 项是对第 n 项的描述. ...

  9. 推荐中的多任务学习-YouTube视频推荐

    本文将介绍Google发表在RecSys'19 的论文<Recommending What Video to Watch Next: A Multitask Ranking System> ...

  10. .Net Core - AgileHttp

    2020年新年将至,先预祝.Net Core越来越好. 做了这么多年一线开发,经常跟Http打交道.比如调用三方的Webservice,比如集成微信支付的时候服务端发起Prepay支付.特别是现在分布 ...