LinkedList插入元素一定比ArrayList快吗
在选择数据结构的时候,我们通常会考虑每种数据结构不同操作的时间复杂度,以及使用场景两个因素。
对于数组,随机元素访问的时间复杂度是 O(1),元素插入操作是 O(n);
对于链表,随机元素访问的时间复杂度是 O(n),元素插入操作是 O(1)。
那么,在大量的元素插入、很少的随机访问的业务场景下,是不是就应该使用 LinkedList 呢?接下来,我们写一段代码测试下两者随机访问和插入的性能吧。
我们定义下面几个方法,分别为随机访问LinkedList数组和ArrayList数组,往LinkedList和ArrayList中随机插入元素。
private static void linkedListGet(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(LinkedList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.get(ThreadLocalRandom.current().nextInt(elementCount)));}
private static void arrayListGet(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(ArrayList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.get(ThreadLocalRandom.current().nextInt(elementCount)));}
private static void linkedListAdd(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(LinkedList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current().nextInt(elementCount), 1));}
private static void arrayListAdd(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(ArrayList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current().nextInt(elementCount), 1));}
测试一下:
我们定义一个10万元素的数组,然后测试访问时间和插入时间,结果如下:
StopWatch '': running time = 4827155600 ns
---------------------------------------------
ns % Task name
---------------------------------------------
4808820500 100% linkedListGet
018335100 000% arrayListGet
StopWatch '': running time = 28181287000 ns
---------------------------------------------
ns % Task name
---------------------------------------------
27238759200 097% linkedListAdd
942527800 003% arrayListAdd
可以很明显的看到ArrayList无论是随机访问,还是随机插入,所需的时间都遥遥领先于LinkedList。
翻看 LinkedList 源码发现,插入操作的时间复杂度是 O(1) 的前提是,你已经有了那个要插入节点的指针。但,在实现的时候,我们需要先通过循环获取到那个节点的 Node,然后再执行插入操作。前者也是有开销的,不可能只考虑插入操作本身的代价:
public void add(int index, E element) {checkPositionIndex(index);
if (index == size)linkLast(element);elselinkBefore(element, node(index));
}
Node<E> node(int index) {// assert isElementIndex(index);
if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}
}
所以,对于插入操作,LinkedList 的时间复杂度其实也是 O(n)。继续做更多实验的话你会发现,在各种常用场景下,LinkedList 几乎都不能在性能上胜出 ArrayList。
我们继续测试一下在尾部插入元素:
private static void linkedListAddLast(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(LinkedList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current().nextInt(elementCount)));}
private static void arrayListAddLast(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(ArrayList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current().nextInt(elementCount)));}
测试参数还是同上,测试结果如下:
StopWatch '': running time = 95097500 ns
---------------------------------------------
ns % Task name
---------------------------------------------
078869800 083% linkedListAddLast
016227700 017% arrayListAddLast
我们继续测试一下在头部插入元素:
private static void linkedListAddFirst(int elementCount, int loopCount) {LinkedList<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(LinkedList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.addFirst(ThreadLocalRandom.current().nextInt(elementCount)));}
private static void arrayListAddFirst(int elementCount, int loopCount) {List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(ArrayList::new));IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(0, ThreadLocalRandom.current().nextInt(elementCount)));}
这次的测试结果如下:
StopWatch '': running time = 1832579700 ns
---------------------------------------------
ns % Task name
---------------------------------------------
087754700 005% linkedListAddFirst
1744825000 095% arrayListAddFirst
总结:
ArrayList在大部分时候的性能都明显要强于LinkedList。即使是对于增删少查询多这一场景。LinkedList只有在头部插入元素的时候,性能会明显优于ArrayList。
LinkedList并没有想象中的那么好用,使用需谨慎。
LinkedList插入元素一定比ArrayList快吗相关推荐
- LinkedList一定比ArrayList的插入和删除效率高吗
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 本文主要看一下,两种List集合,插入删除效率情况,为什么使用ArrayList的情况更多些? Linked ...
- boost::unorder_map如何插入元素_链表和有序二叉树插入元素时真的比数组快吗?
脚本之家 你与百万开发者在一起 作者 | focuscode出品 | 脚本之家(ID:jb51net) 公司有位C++标准委员会的顾问大佬,一年会有几次视频讲座,分享一些编程要点或者经验.很多时候都是 ...
- ArrayList 与 LinkedList 插入、查询效率测试
嗨喽-小伙伴们我又来了, 今天闲得没事干,来水一片文章(bushi), 不知道大伙们还记不记得数据结构中顺序表和链表的使用场景,正好昨天有位朋友给我发了一张程序运行结果的截图: 他说他在测试比较Arr ...
- java linkedlist 查找_Java中LinkedList真的是查找慢增删快
测试结果 废话不多说,先上测试结果.作者分别在ArrayList和LinkedList的头部.尾部和中间三个位置插入与查找100000个元素所消耗的时间来进行对比测试,下面是测试结果 (感谢@Hosa ...
- LinkedList 真的是查找慢增删快?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源:juejin.im/post/5c00987de5 ...
- java 向List最前面插入元素
Java List ArrayList.LinkedList 添加一条数据到list首位 Map<String, Object> map = new HashMap<String, ...
- java数组怎样插入元素,Java如何在给定位置将元素插入数组?
众所周知,Java中的数组是固定大小的对象,一旦创建,数组的大小就无法更改.因此,如果您希望有一个可调整大小的类似数组的对象,可以在给定位置插入元素,则可以使用java.util.List对象类型. ...
- 单链表插入元素 注释 c语言,数据结构之无头单链表的相关练习题——C语言实现(详细注释)...
本文中所用到的相关链表操作实现均在我上篇博客中:https://blog..net/haoziai905/article/details/87099287 1.删除无头单链表的非尾结点 这道题的重点就 ...
- 向一个数组中插入元素
向一个数组中插入元素是平时很常见的一件事情.你可以使用push在数组尾部插入元素,可以用unshift在数组头部插入元素,也可以用splice在数组中间插入元素. 但是这些已知的方法,并不意味着没有更 ...
最新文章
- 电动汽车:新一轮三年十倍,“补贴”结束“高端”开启
- CSS的一些基础知识
- C++longest common subsequence最长公共子序列的实现(附完整源码)
- 计算机与现代教育技术论文开题报告,计算机科学技术大学硕士与本科毕业论文开题报告...
- Django小项目简单BBS论坛
- netty发送对象消息
- SpringMVC框架搭建
- PHP 循环时间控制缓冲方法
- Java数组的三种打印方式
- 阿里云短信验证第三方接口(快速使用)
- Slate轨道工具使用(一)—Track,Clip
- 我的PCB设计经验——奥研电子整理
- 新品开源又融资,长亭科技“脱胎而成”!
- 信号完整性问题的11个基本原则(伯格丁原则)
- PAT乙级 1003 我要通过! (20分)
- 惠普局域网共享打印机设置_Windows7局域网共享打印机教程,HP M1136 MFP打印机共享方法...
- Compression-Expansion Coding Improvements in MLC/TLC NVM论文解读
- 【读书笔记】数学之美
- fiddler mac
- 时空大数据可视化专栏
热门文章
- buuctf N种方法解决
- nginx.conf配置文件
- 思想解读:optee中的多线程处理
- [architecture]-处理器的顺序和乱序执行
- [crypto]-52-python3中rsa(签名验签加密解密)aes(ecb cbc ctr)hmac的使用,以及unittest测试用
- Raft 集群成员变更、日志压缩、客户端交互
- checked_delete问题: Beyond the C++ STL: an introduction to boostdeleter::do_it
- java小程序死机_求解,刚写的小程序,一运行我机器就死机
- 【网络安全】文件上传绕过思路总结
- 【网络安全】Metasploit 生成的 Shellcode 的导入函数解析以及执行流程分析(1)