热门标签 | 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!!


推荐阅读
  • 本文探讨了在C++中如何有效地清空输入缓冲区,确保程序只处理最近的输入并丢弃多余的输入。我们将介绍一种不阻塞的方法,并提供一个具体的实现方案。 ... [详细]
  • 深入解析for与foreach遍历集合时的性能差异
    本文将详细探讨for循环和foreach(迭代器)在遍历集合时的性能差异,并通过实际代码示例和源码分析,帮助读者理解这两种遍历方式的不同之处。文章内容丰富且专业,旨在为编程爱好者提供有价值的参考。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本题探讨了在一个有向图中,如何根据特定规则将城市划分为若干个区域,使得每个区域内的城市之间能够相互到达,并且划分的区域数量最少。题目提供了时间限制和内存限制,要求在给定的城市和道路信息下,计算出最少需要划分的区域数量。 ... [详细]
  • 本问题探讨了在特定条件下排列儿童队伍的方法数量。题目要求计算满足条件的队伍排列总数,并使用递推算法和大数处理技术来解决这一问题。 ... [详细]
  • 深入理解Lucene搜索机制
    本文旨在帮助读者全面掌握Lucene搜索的编写步骤、核心API及其应用。通过详细解析Lucene的基本查询和查询解析器的使用方法,结合架构图和代码示例,带领读者深入了解Lucene搜索的工作流程。 ... [详细]
  • 异常要理解Java异常处理是如何工作的,需要掌握一下三种异常类型:检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常ÿ ... [详细]
  • 本文详细解析了Java中hashCode()和equals()方法的实现原理及其在哈希表结构中的应用,探讨了两者之间的关系及其实现时需要注意的问题。 ... [详细]
  • 本文将探讨Java编程语言中对象和类的核心概念,帮助读者更好地理解和应用面向对象编程的思想。通过实际例子和代码演示,我们将揭示如何在Java中定义、创建和使用对象。 ... [详细]
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • Java 实现二维极点算法
    本文介绍了一种使用 Java 编程语言实现的二维极点算法。该算法用于从一组二维坐标中筛选出极点,适用于需要处理几何图形和空间数据的应用场景。文章不仅详细解释了算法的工作原理,还提供了完整的代码示例。 ... [详细]
  • PHP 实现多级树形结构:构建无限层级分类系统
    在众多管理系统中,如菜单、分类和部门等模块,通常需要处理层级结构。为了高效管理和展示这些层级数据,本文将介绍如何使用 PHP 实现多级树形结构,并提供代码示例以帮助开发者轻松实现无限分级。 ... [详细]
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社区 版权所有