LinkedList与ArrayList性能分析和适用场景

@TOC

LinkedList与ArrayList性能分析和适用场景

网上的信息比较驳杂,所以自己写测试测一测

在索引中间位置同时进行删除、插入操作性能测试

集合size为100时

java 复制代码
@Test
	void test23() {
		ArrayList<Double> list = new ArrayList<>();
		for (int i = 0; i < 100; i++) {
			list.add(Math.random());
		}
		Double x = 2.33333;
		ArrayList<Double> list1 = new ArrayList<>(list);
		LinkedList<Double> list2 = new LinkedList<>(list);
		
		//在ArrayList索引中间位置进行删除、插入操作性能测试
		long start1 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list1.remove(50);
			list1.add(50, x);
		}
		long time1 = System.currentTimeMillis()-start1;
		System.out.println("arraylist耗时:"+time1);
		//在LinkedList索引中间位置进行删除、插入操作性能测试
		long start2 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list2.remove(50);
			list2.add(50, x);
		}
		long time2 = System.currentTimeMillis()-start2;
		System.out.println("linkedlist耗时:"+time2);				
	}

集合size为1000时

java 复制代码
@Test
	void test23() {
		ArrayList<Double> list = new ArrayList<>();
		for (int i = 0; i < 1000; i++) {
			list.add(Math.random());
		}
		Double x = 2.33333;
		ArrayList<Double> list1 = new ArrayList<>(list);
		LinkedList<Double> list2 = new LinkedList<>(list);
		
		//在ArrayList索引中间位置进行删除、插入操作性能测试
		long start1 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list1.remove(500);
			list1.add(500, x);
		}
		long time1 = System.currentTimeMillis()-start1;
		System.out.println("arraylist耗时:"+time1);
		//在LinkedList索引中间位置进行删除、插入操作性能测试
		long start2 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list2.remove(500);
			list2.add(500, x);
		}
		long time2 = System.currentTimeMillis()-start2;
		System.out.println("linkedlist耗时:"+time2);			
	}

经测试: size为100时,100万次中间位置的删除添加,ArrayList耗时91ms,LinkedList耗时174ms。 size为1000时,100万次中间位置的删除添加,ArrayList耗时123ms,LinkedList耗时1421ms。 可见size越大,对LinkedList在中间位置的增删性能影响越大,考虑到LinkedList底层是双向链表结构,如果仅仅增删的话性能消耗很小,所以实际影响增删性能的是LinkedList定位到中间索引的消耗,LinkedList定位索引(可以说LinkedList不具有原生索引),必须采取遍历的方法,从头部遍历到中间位置,所以,size越大,遍历消耗就越大,ArrayList底层是动态数组,具有原生的索引,所以定位索引非常快,性能消耗主要在动态生成新的数组上,问题是这里每次都是插入一个,删除一个,size大小是不变的,所以并不需要生成新的数组,于是此时ArrayList等价于一个固定长度的数组,虽然增删操作会修改后半部分元素的索引,但效率依然极高。

在索引头尾进行删除、插入操作性能测试

集合size为1000时

java 复制代码
@Test
	void test23() {
		ArrayList<Double> list = new ArrayList<>();
		for (int i = 0; i < 1000; i++) {
			list.add(Math.random());
		}
		Double x = 2.33333;
		ArrayList<Double> list1 = new ArrayList<>(list);
		LinkedList<Double> list2 = new LinkedList<>(list);
		
		//在ArrayList索引末尾添加删除操作
		long start1 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list1.remove(list1.size()-1);
			list1.add(x);
		}
		long time1 = System.currentTimeMillis()-start1;
		System.out.println("在ArrayList索引末尾添加删除操作:"+time1);
		//在ArrayList索引头部添加删除操作
		long start11 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list1.remove(0);
			list1.add(0,x);
		}
		long time11 = System.currentTimeMillis()-start11;
		System.out.println("在ArrayList索引头部添加删除操作:"+time11);
		//在ArrayList索引头部添加,在尾部删除操作
		long start111 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list1.add(0,x);
			list1.remove(list1.size()-1);			
		}
		long time111 = System.currentTimeMillis()-start111;
		System.out.println("在ArrayList索引头部添加,在尾部删除操作:"+time111);
		//在LinkedList索引末尾添加删除操作
		long start2 = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list2.removeLast();
			list2.addLast(x);
		}
		long time2 = System.currentTimeMillis()-start2;
		System.out.println("在LinkedList索引末尾添加删除操作:"+time2);
		//在LinkedList索引头部添加删除操作
		long start22= System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list2.removeFirst();
			list2.addFirst(x);
		}
		long time22 = System.currentTimeMillis()-start22;
		System.out.println("在LinkedList索引头部添加删除操作:"+time22);
		//在LinkedList索引头部添加,在尾部删除操作
		long start222= System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			list2.removeLast();
			list2.addFirst(x);
		}
		long time222 = System.currentTimeMillis()-start222;
		System.out.println("在LinkedList索引头部添加,在尾部删除操作:"+time222);				
	}

经测试: 在ArrayList索引末尾添加删除操作:23ms 在ArrayList索引头部添加删除操作:204ms 在ArrayList索引头部添加,在尾部删除操作:109ms 在LinkedList索引末尾添加删除操作:22ms 在LinkedList索引头部添加删除操作:24ms 在LinkedList索引头部添加,在尾部删除操作:18ms

可见,LinkedList在头尾部的操作性能,大部分时候是远超ArrayList的,这是因为LinkedList底层是双向链表结构,与中间位置的操作相比,头尾部的操作,不涉及索引定位,也不涉及其他元素索引的改变(链表的逻辑顺序是通过链表中的指针链接次序实现的,无原生索引),ArrayList虽然也不需要遍历索引,是直接按索引定位的,但是,增删头部的元素,都会导致其他元素索引的改变,所以可以看到ArrayList在索引末尾增删性能最高,因为无需修改其他元素的索引,头部添加,在尾部删除的性能其次,因为头部添加操作需要修改其他元素的索引,头部添加删除操作最次,因为添加和删除都会需要修改其他元素的索引。

总结:如果你需要指定索引的增删改查,那么选择ArrayList,如果你需要头尾部的增删改查,经常出栈入栈(后进先出),出队入队(先进先出),那么选择LinkedList

相关推荐
武子康20 分钟前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘1 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上2 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人3 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.3 小时前
Mybatis-Plus
java·开发语言
不良人天码星3 小时前
lombok插件不生效
java·开发语言·intellij-idea
守护者1703 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云3 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台