热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

较真,ArrayList和LinkList增加,插入速度比较,代码详解

网上有很多ArrayList和LinkList的各种对比,以前学习这两个集合的时候老师讲的是:查询ArrayList快,新增和删除Link

网上有很多ArrayList和LinkList的各种对比,以前学习这两个集合的时候老师讲的是:查询ArrayList快,新增和删除LinkLink快。需要频繁查询用ArrayList,需要频繁增删用LinkLink。
但是网上百度的话说法又不一样。
下面就上代码测试吧:(测试是使用的JDK1.8其他版本结论可能不同,不做版本更变测试)

//先测试新增速度,使用add()方法 先插入10000条数据比较
//比较速度的时候为了不影响 要单独跑 不能两个列表同时插入
public static void main(String[] args){List<String> array = new ArrayList<String>();LinkedList<String> link = new LinkedList<String>();//array 插入long startlist = System.currentTimeMillis();for(int i = 0; i < 10000; i ++){array.add("123"+i);}long endTime = System.currentTimeMillis();System.out.println("array="+(endTime-startlist));//link插入/** long startlist2 = System.currentTimeMillis();for(int i = 0; i <10000; i ++){link.add("123"+i);}long endTime2 = System.currentTimeMillis();System.out.println("link="+(endTime2-startlist2));*/}//分别运行3次//array=10 array=9 array=10// link=10 link=10 link=10

可以得出结论 在添加10000条数据的时候 两个数组几乎没差别。
继续测试,还是刚才代码,把for循环里面参数改为1000000,

一样 分别运行3次得出结果
array=577 array=518 array=537
link=778 link=752 link=691
得出结果 arrayList在新增百万数据时要快一点,但是差别也不大

再加大数据(我IDEA跑的 再加到1000W循环是保存内存溢出 加大了JVM内存空间再战!!!):

一样 分别运行3次得出结果
link=6628 link=6873 link=6469
array=5934 array=5725 array=5767实际证明 千万数据新增还是ArrayList要快一点。

是不是感觉已经推翻了以前学到的东西,不急,下面来分别研究两个集合在新增的时候到底做了什么操作,上源码:

在这里插入代码片

结论 在不修改指针的时候,就算ArrayList发生了扩容copy操作,在往数据末尾新增的时候速度还是比LinkList速度快。

//ArrayList源码:
public boolean add(E e) {//增加数组大小(指针移动) 如果需要就扩容ensureCapacityInternal(size + 1); //元素赋值elementData[size++] = e;return true;}//ensureCapacityInternal方法 判断是否小于数组初始值10private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}//当前数组+1 如果大于当前数组长度就进行扩容
private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}//这个就是扩容的最本质方法了 新建一个1.5倍长度的数组,在把老数组拷贝过来。copyOf方法使用的是 native void arraycopy 效率很快private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);}

下面是LinkList源码分析:

//linkList的add方法看起来就简单了很多public boolean add(E e) {linkLast(e);return true;}
//找到最好一个参数 创建一个新的Node对象直接新增,修改前一个Node对象,看上去很简单,但是实际上新增了一个对象,修改了一个对象。void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;}

继续测试,测试插入方法,一样的测试代码

public static void main(String[] args){ArrayList<String> array = new ArrayList<String>();LinkedList<String> link = new LinkedList<String>();//先创建数据for(int i = 0; i < 10000; i ++){link.add("123"+i);}//插入新数据long startlist2 = System.currentTimeMillis();for(int i = 0; i < 100000; i ++){link.add(0,"123"+i);}long endTime2 = System.currentTimeMillis();System.out.println("link="+(endTime2-startlist2));//还是分别执行 互不影响/* for(int i = 0; i <10000; i ++){array.add("123"+i);}long startlist = System.currentTimeMillis();for(int i = 0; i <100000; i ++){array.add(0,"123"+i);}long endTime = System.currentTimeMillis();System.out.println("array="+(endTime-startlist));*/}//分别执行3次 看结果//link=63 link=58 link=65//array=3469 array=3398 array=3244

插入速度通过测试得出,linkList直接完爆ArrayList,
这又是为什么呢???
上源码:

//ArrayList 插入方法
public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1); // Increments modCount!!//这里可以看出 插入的时候 是直接调用的arraycopy copy了一个新的数组System.arraycopy(elementData, index, elementData, index + 1,size - index);elementData[index] = element;size++;}

ArrayList很粗暴的每次插入都在复制新的数组,

//linkList 先判断是不是最后一个,最好一个调用和刚才新增一样的方法创建对象,不是最后一个
public void add(int index, E element) {checkPositionIndex(index);if (index == size)linkLast(element);elselinkBefore(element, node(index));}
//不是最后一个 使用插入方法,新增对象,修改所以对象指针。
void linkBefore(E e, Node<E> succ) {// assert succ != null;final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;}

可以得出最终结论,在新增对象的时候两个集合ArrayList要快一点,但是基本没什么区别。
但是在插入操作的时候,LinkList效率完爆ArrayList。

最后在补充一下两个数组删除remove方法的效率差距:

//这是ArrayList的remove源码 这里可以看出 删除方法也是调用arraycopy
public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue;}//而LinkList依旧只是在对节点对象进行操作public E remove(int index) {checkElementIndex(index);return unlink(node(index));}E unlink(Node<E> x) {// assert x != null;final E element = x.item;final Node<E> next = x.next;final Node<E> prev = x.prev;if (prev == null) {first = next;} else {prev.next = next;x.prev = null;}if (next == null) {last = prev;} else {next.prev = prev;x.next = null;}x.item = null;size--;modCount++;return element;}

由此可见,LinkList在删除的效率上依旧完爆ArrayList。
注:以上源码只针对JDK1.8!!


推荐阅读
  • spring boot使用jetty无法启动 ... [详细]
  • 本文将详细介绍如何使用Java编程语言生成指定数量的不重复随机数,包括具体的实现方法和代码示例。适合初学者和有一定基础的开发者参考。 ... [详细]
  • Go从入门到精通系列视频之go编程语言密码学哈希算法(二) ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • importjava.io.*;importjava.util.*;publicclass五子棋游戏{staticintm1;staticintn1;staticfinalintS ... [详细]
  • 本文通过C++语言实现了一个递归算法,用于解析并计算数学表达式的值。该算法能够处理加法、减法、乘法和除法操作。 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • 本文详细介绍了C++中的构造函数,包括其定义、特点以及如何通过构造函数进行对象的初始化。此外,还探讨了转换构造函数的概念及其在不同情境下的应用,以及如何避免不必要的隐式类型转换。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.jena.atlas.lib.ByteBufferLib 类下的 acopyArray 方法,并提供了多个实际应用中的代码示例,帮助开发者更好地理解和使用该方法。 ... [详细]
  • Java中如何判断一个对象是否为Long类型
    本文介绍了一种在Java中判断对象是否属于Long类型的方法,通过定义一个特定的方法来实现这一功能,该方法能够准确地识别并返回结果。 ... [详细]
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • 数据类型--char一、char1.1char占用2个字节char取值范围:【0~65535】char采用unicode编码方式char类型的字面量用单引号括起来char可以存储一 ... [详细]
  • 本文介绍如何手动实现一个字符串连接函数,该函数不依赖于C语言的标准字符串处理函数,如strcpy或strcat。函数原型为void concatenate(char *dest, char *src),其主要作用是将源字符串src追加到目标字符串dest的末尾。 ... [详细]
  • 本文通过分析一个具体的案例,探讨了64位Linux系统对32位应用程序的兼容性问题。案例涉及OpenVPN客户端在64位系统上的异常行为,通过逐步排查和代码测试,最终定位到了与TUN/TAP设备相关的系统调用兼容性问题。 ... [详细]
  • 本文介绍如何使用JavaScript中的for循环来创建一个九九乘法表,适合初学者学习循环结构的应用。 ... [详细]
author-avatar
____晨宝_507
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有