在选择数据结构的时候,我们通常会考虑每种数据结构不同操作的时间复杂度,以及使用场景两个因素。

对于数组,随机元素访问的时间复杂度是 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快吗相关推荐

  1. LinkedList一定比ArrayList的插入和删除效率高吗

    ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 本文主要看一下,两种List集合,插入删除效率情况,为什么使用ArrayList的情况更多些? Linked ...

  2. boost::unorder_map如何插入元素_链表和有序二叉树插入元素时真的比数组快吗?

    脚本之家 你与百万开发者在一起 作者 | focuscode出品 | 脚本之家(ID:jb51net) 公司有位C++标准委员会的顾问大佬,一年会有几次视频讲座,分享一些编程要点或者经验.很多时候都是 ...

  3. ArrayList 与 LinkedList 插入、查询效率测试

    嗨喽-小伙伴们我又来了, 今天闲得没事干,来水一片文章(bushi), 不知道大伙们还记不记得数据结构中顺序表和链表的使用场景,正好昨天有位朋友给我发了一张程序运行结果的截图: 他说他在测试比较Arr ...

  4. java linkedlist 查找_Java中LinkedList真的是查找慢增删快

    测试结果 废话不多说,先上测试结果.作者分别在ArrayList和LinkedList的头部.尾部和中间三个位置插入与查找100000个元素所消耗的时间来进行对比测试,下面是测试结果 (感谢@Hosa ...

  5. LinkedList 真的是查找慢增删快?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源:juejin.im/post/5c00987de5 ...

  6. java 向List最前面插入元素

    Java List ArrayList.LinkedList 添加一条数据到list首位 Map<String, Object> map = new HashMap<String, ...

  7. java数组怎样插入元素,Java如何在给定位置将元素插入数组?

    众所周知,Java中的数组是固定大小的对象,一旦创建,数组的大小就无法更改.因此,如果您希望有一个可调整大小的类似数组的对象,可以在给定位置插入元素,则可以使用java.util.List对象类型. ...

  8. 单链表插入元素 注释 c语言,数据结构之无头单链表的相关练习题——C语言实现(详细注释)...

    本文中所用到的相关链表操作实现均在我上篇博客中:https://blog..net/haoziai905/article/details/87099287 1.删除无头单链表的非尾结点 这道题的重点就 ...

  9. 向一个数组中插入元素

    向一个数组中插入元素是平时很常见的一件事情.你可以使用push在数组尾部插入元素,可以用unshift在数组头部插入元素,也可以用splice在数组中间插入元素. 但是这些已知的方法,并不意味着没有更 ...

最新文章

  1. 电动汽车:新一轮三年十倍,“补贴”结束“高端”开启
  2. CSS的一些基础知识
  3. C++longest common subsequence最长公共子序列的实现(附完整源码)
  4. 计算机与现代教育技术论文开题报告,计算机科学技术大学硕士与本科毕业论文开题报告...
  5. Django小项目简单BBS论坛
  6. netty发送对象消息
  7. SpringMVC框架搭建
  8. PHP 循环时间控制缓冲方法
  9. Java数组的三种打印方式
  10. 阿里云短信验证第三方接口(快速使用)
  11. Slate轨道工具使用(一)—Track,Clip
  12. 我的PCB设计经验——奥研电子整理
  13. 新品开源又融资,长亭科技“脱胎而成”!
  14. 信号完整性问题的11个基本原则(伯格丁原则)
  15. PAT乙级 1003 我要通过! (20分)
  16. 惠普局域网共享打印机设置_Windows7局域网共享打印机教程,HP M1136 MFP打印机共享方法...
  17. Compression-Expansion Coding Improvements in MLC/TLC NVM论文解读
  18. 【读书笔记】数学之美
  19. fiddler mac
  20. 时空大数据可视化专栏

热门文章

  1. buuctf N种方法解决
  2. nginx.conf配置文件
  3. 思想解读:optee中的多线程处理
  4. [architecture]-处理器的顺序和乱序执行
  5. [crypto]-52-python3中rsa(签名验签加密解密)aes(ecb cbc ctr)hmac的使用,以及unittest测试用
  6. Raft 集群成员变更、日志压缩、客户端交互
  7. checked_delete问题: Beyond the C++ STL: an introduction to boostdeleter::do_it
  8. java小程序死机_求解,刚写的小程序,一运行我机器就死机
  9. 【网络安全】文件上传绕过思路总结
  10. 【网络安全】Metasploit 生成的 Shellcode 的导入函数解析以及执行流程分析(1)