什么情况下ArrayList增删 比LinkedList 更快
public static void main(String[] args){
final int MAX_VAL = 10000;
List<Integer> linkedList = new LinkedList<Integer>();
List<Integer> arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
long time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(MAX_VAL/2, i);
}
System.out.println("LL time: " + (System.nanoTime() - time));
time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
arrayList.add(MAX_VAL/2, i);
}
System.out.println("AL time: " + (System.nanoTime() - time));
}
从中间插入结果:

怎么会这样, 不应该是LinkedList更快吗? ArrayList底层是数组, 添加数据需要移动后面的数据, 而LinkedList使用的是链表, 直接移动指针就行, 按理说应该是LinkedList更快.
再来看
从尾插入
public static void main(String[] args){
final int MAX_VAL = 10000;
List<Integer> linkedList = new LinkedList<Integer>();
List<Integer> arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
long time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
}
System.out.println("LL time: " + (System.nanoTime() - time));
time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
arrayList.add(i);
}
System.out.println("AL time: " + (System.nanoTime() - time));
}

从头开始插入
public static void main(String[] args){
final int MAX_VAL = 10000;
List<Integer> linkedList = new LinkedList<Integer>();
List<Integer> arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
long time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(0,i);
}
System.out.println("LL time: " + (System.nanoTime() - time));
time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
arrayList.add(0,i);
}
System.out.println("AL time: " + (System.nanoTime() - time));
}
结果

然后从三分之一的位置开始插入
结果

从三分之二的位置插入
结果

源码部分
LinkedList源码
// 在index前添加节点,且节点的值为element
public void add(int index, E element) {
addBefore(element, (index==size ? header : entry(index)));
} // 获取双向链表中指定位置的节点
private Entry<E> entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry<E> e = header;
// 获取index处的节点。
// 若index < 双向链表长度的1/2,则从前向后查找;
// 否则,从后向前查找。
if (index < (size >> 1)) {
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
} // 将节点(节点数据是e)添加到entry节点之前。
private Entry<E> addBefore(E e, Entry<E> entry) {
// 新建节点newEntry,将newEntry插入到节点e之前;并且设置newEntry的数据是e
Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
// 插入newEntry到链表中
newEntry.previous.next = newEntry;
newEntry.next.previous = newEntry;
size++;
modCount++;
return newEntry;
从中,我们可以看出:通过add(int index, E element)向LinkedList插入元素时。先是在双向链表中找到要插入节点的位置index;找到之后,再插入一个新节点。
双向链表查找index位置的节点时,有一个加速动作:若index < 双向链表长度的1/2,则从前向后查找; 否则,从后向前查找。
接着,我们看看ArrayList.java中向指定位置插入元素的代码。如下:
// 将e添加到ArrayList的指定位置
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
ensureCapacity(size+1) 的作用是“确认ArrayList的容量,若容量不够,则增加容量。”
真正耗时的操作是 System.arraycopy(elementData, index, elementData, index + 1, size - index);
实际上,我们只需要了解: System.arraycopy(elementData, index, elementData, index + 1, size - index); 会移动index之后所有元素即可。这就意味着,ArrayList的add(int index, E element)函数,会引起index之后所有元素的改变!
结论:
现在大概知道了,插入位置的选取对LinkedList有很大的影响,一直往数据中间部分插入删除的时候,ArrayList比LinkedList更快
原因大概就是当数据量大的时候,system.arraycopy的效率要比每次插入LinkedList都需要从端查找index和分配节点node来的更快。
总之,对于99%或更多的现实情况,ArrayList是更好的选择,并且利用LinkedList的狭隘优势需要非常小心。
什么情况下ArrayList增删 比LinkedList 更快的更多相关文章
- java.util.ArrayList,java.util.LinkedList,java.util.Vector的区别,使用场合.
下图是Collection的类继承图 从图中可以看出:Vector.ArrayList.LinkedList这三者都实现了List 接口.所有使用方式也很相似,主要区别在于实现方式的不同,所以对不同的 ...
- java里的数组和list分别在什么情况下使用?
数组长度固定,List未限定长度,且支持的功能更多,最常用的ArrayList底层实际上也是使用数组实现. 不需要复杂功能和确定长度的情况下,使用数组效率更高,通常情况建议使用List.
- 什么情况用ArrayList or LinkedList呢?
ArrayList 和 LinkedList 是 Java 集合框架中用来存储对象引用列表的两个类.ArrayList 和 LinkedList 都实现 List 接口.先对List做一个简单的了解: ...
- 使用QFileInfo类获取文件信息(在NTFS文件系统上,出于性能考虑,文件的所有权和权限检查在默认情况下是被禁用的,通过qt_ntfs_permission_lookup开启和操作。absolutePath()必须查询文件系统。而path()函数,可以直接作用于文件名本身,所以,path() 函数的运行会更快)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Amnes1a/article/details/65444966QFileInfo类为我们提供了系统无 ...
- OC JS交互(通常情况下,如果网页写得正规的话,是可以正常交互的,之前就遇到后台写h5始终拿不到事件,元素也拿不到,更别说交互了,真是奇了怪了)
自动填充表单 @"document.getElementById('loginid').value = '这里填入你的用户名';document.getElementById('userpa ...
- Java高并发情况下的锁机制优化
本文主要讲并行优化的几种方式, 其结构如下: 锁优化 减少锁的持有时间 例如避免给整个方法加锁 1 public synchronized void syncMethod(){ 2 othercode ...
- 如何彻底理解Java抽象类 为什么要用抽象类 什么情况下用抽象类
如何彻底理解Java抽象类 为什么要用抽象类 什么情况下用抽象类 呐,到底什么是抽象类,有时明明一个普通类就可以解决了,为啥非得整个抽象类,装逼吗 我曾带着这样的疑惑,查了很多资料,看了很多源码,写了 ...
- Redis面试题记录--缓存双写情况下导致数据不一致问题
转载自:https://blog.csdn.net/lzhcoder/article/details/79469123 https://blog.csdn.net/u013374645/article ...
- 用SignalR 2.0开发客服系统[系列4:负载均衡的情况下使用SignalR]
前言 交流群:195866844 目录: 用SignalR 2.0开发客服系统[系列1:实现群发通讯] 用SignalR 2.0开发客服系统[系列2:实现聊天室] 用SignalR 2.0开发客服系统 ...
随机推荐
- 01-Javascript简介
Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) JavaScript的组成 Java ...
- 解决mac安装homebrew后报错-bash: brew: command not found
解决mac安装homebrew后报错-bash: brew: command not found 参照官网上很简单的一句安装命令, /usr/bin/ruby -e "$(curl ...
- Java Applet小应用
开发和部署方式 嵌入到HTML网页中,用<Applet></Applet>标签识别.java环境用浏览器的,在第一次打开时下载,可开发成以后打开,默认不必再次下载.也可 ...
- (转)类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET BCL里有哪些是类(结构),为什么它们不是结构(类)?在自定义类型时,您如何选择是类还是结构?
转自:http://blog.csdn.net/lingxyd_0/article/details/8695747 类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET B ...
- Java Application和Java Applet的区别
Java Applet和Java Application在结构方面的主要区别表现在: (1)运行方式不同.Java Applet程序不能单独运行,它必须依附于一个用HTML语言编写的网页并嵌入其中,通 ...
- centos下添加epel源
RHEL以及他的衍生发行版如CentOS.Scientific Linux为了稳定,官方的rpm repository提供的rpm包往往是很滞后的,当然了,这样做这是无可厚非的,毕竟这是服务器版本,安 ...
- Django:model中的ForeignKey理解
有两个数据模型栏目模型和文章模型ArticleColumn和ArticlePost ArticleColumn: class ArticleColumn(models.Model): # 用户与栏目是 ...
- 添加vscode自定义代码块
以vue为例 一.打开vscode>文件>首选项>用户代码片段>vue.json二.编写代码块 其中一行一句:$1是占位符,就是你可以输入的地方."http get& ...
- MVC 5 Strongly Typed Views(强类型视图)
学习MVC这样久以来,发觉网站上很多MVC的视频或是文章,均是使用Strongly Type views来实现控制器与视图的交互.Insus.NET以前发布的博文中,也大量使用这种方式: <Da ...
- 利用koa打造restful API
概述 最近学习利用koa搭建API接口,小有所得,现在记录下来,供以后开发时参考,相信对其他人也有用. 就目前我所知道的而言,API有2种,一种是jsonp这种API,前端通过ajax来进行跨域请求获 ...