ArrayList与LinkedList比较
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)。
- 末端插入,虽然二者都是O(1),但是LinkedList每次插入都要new一个对象。因此,当数据量小时,LinkedList速度快,随着数据量的增加,ArrayList速度更快。
- 随机插入
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比较的更多相关文章
- 深入理解java中的ArrayList和LinkedList
杂谈最基本数据结构--"线性表": 表结构是一种最基本的数据结构,最常见的实现是数组,几乎在每个程序每一种开发语言中都提供了数组这个顺序存储的线性表结构实现. 什么是线性表? 由0 ...
- ArrayList,Vector,LinkedList
在java.util包中定义的类集框架其核心的组成接口有如下:·Collection接口:负责保存单值的最大父接口 |-List子接口:允许保存重复元素,数据的保存顺序就是数据的增加顺序: |-Set ...
- Java数据结构之表的增删对比---ArrayList与LinkedList之一
一.Java_Collections表的实现 与c不同Java已经实现并封装了现成的表数据结构,顺序表以及链表. 1.ArrayList是基于数组的实现,因此具有的特点是:1.有索引值方便查找,对于g ...
- C++模拟实现JDK中的ArrayList和LinkedList
Java实现ArrayList和LinkedList的方式采用的是数组和链表.以下是用C++代码的模拟: 声明Collection接口: #ifndef COLLECTION_H_ #define C ...
- ArrayList与LinkedList用法与区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedLis ...
- ArrayList vs LinkedList vs Vector
List概览 List,正如它的名字,表明其是有顺序的.当讨论List的时候,最好拿它跟Set作比较,Set中的元素是无序且唯一:下面是一张类层次结构图,从这张图中,我们可以大致了解java集合类的整 ...
- ArrayList 和 LinkedList 的区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构.2.对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动 ...
- ArrayList和LinkedList的几种循环遍历方式及性能对比分析(转)
主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论. 通过本文你可以 ...
- ArrayList和LinkedList的几种循环遍历方式及性能对比分析
最新最准确内容建议直接访问原文:ArrayList和LinkedList的几种循环遍历方式及性能对比分析 主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性 ...
- 集合中list、ArrayList、LinkedList、Vector的区别、Collection接口的共性方法以及数据结构的总结
List (链表|线性表) 特点: 接口,可存放重复元素,元素存取是有序的,允许在指定位置插入元素,并通过索引来访问元素 1.创建一个用指定可视行数初始化的新滚动列表.默认情况下,不允许进行多项选择. ...
随机推荐
- vue(axios)封装,content-type由application/json转换为application/x-www-form-urlencoded
现在主流的http请求头的content-type有三种(不讨论xml): application/x-www-form-urlencoded 最常见的提交数据方式,与原生form表单数据一致,在c ...
- 20191017-5 alpha week 2/2 Scrum立会报告+燃尽图 04
此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/9801 小组名称:“组长”组 组长:杨天宇 组员:魏新,罗杨美慧,王歆瑶,徐 ...
- $Poj1952\ $洛谷$1687\ Buy\ Low,Buy\ Lower$ 线性$DP+$方案计数
Luogu Description 求一个长度为n的序列a的最长下降子序列的长度,以及这个长度的子序列种数,注意相同的几个子序列只能算作一个子序列. n<=5000,a[i]不超过long范围 ...
- Ant Design框架中不同的组件访问不同的models中的数据
Ant Design框架中不同的组件访问不同的models中的数据 本文记录了我在使用该框架的时候踩过的坑,方便以后查阅. 一.models绑定 在某个组件(控件或是页面),要想从某个models中获 ...
- 详解Spring IoC容器
一.Spring IoC容器概述 1.依赖反转(依赖注入):依赖对象的获得被反转了. 如果合作对象的引用或依赖关系的管理由具体对象来完成,会导致代码的高度耦合和可测试性的降低,这对复杂的面向对象系统的 ...
- PHP计算每月几周,每周的开始结束日期
PHP计算每月几周,每周的开始结束日期 因为项目中需要一个每周工作计算的功能,具体日期的算法是,把每月拆分成几个周,最后一个星期这个月份的天数不够就补上下个月的. 列如今天8月27星期一,这个月有31 ...
- react-antd-input-onPressEnter
2020-01-11 ant-Design ,Input , onPressEnter 和 onChange 的区别 需求:看下图,右边栏配置开关组件的内容.输入内容,不想要左边实时更改 原来的代码: ...
- SpringBoot+Neo4j在社交电商中,讲述你是怎么被绑定为下线的
上两篇文章我们主要讲解了Neo4j的基本知识以及Neo4j的基本使用,这篇文章我们就以实例来深入的理解一下,我们以社交电商中的绑定关系为例,使用SpringBoot+Neo4j来实现. Neo4j文章 ...
- 深入理解vue的watch
深入理解vue的watch vue中的wactch可以监听到data的变化,执行定义的回调,在某些场景是很有用的,本文将深入源码揭开watch额面纱 前言 watch的使用 watch的多种使用方式 ...
- MariaDB的备份与主从、高可用实践
1.编写脚本,支持让用户自主选择,使用mysqldump还是xtraback全量备份. [root@test-centos7-node1 scripts]# cat chose_backup_mysq ...