当前位置: 首页 > article >正文

ArrayList与LinkList的区别

ArrayList底层的实现是Array, 数组扩容实现

  •  新增数据空间判断,  新增数据的时候需要判断当前是否有空闲空间存储
  • 扩容需要申请新的连续空间,把老的数组复制过去

  • 新增新的内容, 回收老的数组空间

LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能, 但是再查找方面弱于ArrayList, 当然,这些对比都是指数据量很大或者操作很频繁

 链表不需要连续的空间, 大小不确定

 1. 底层实现

ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;

2. 时间复杂度

操作            数组    链表
随机访问    O(1)     O(N)
头部插入    O(N)    O(1)
头部删除    O(N)    O(1)
尾部插入    O(1)     O(1)
尾部删除    O(1)     O(1)
查询对象所在索引 O(n) O(n)

查询对象所在索引时间复杂度都是O(N)

  • 数组要比链表快因为数组的连续内存, 会有一部分或者全部数据一起进入到CPU缓存, 而链表还需要在去内存中根据上下游标查找, CPU缓存比内存块太多
  • 从源码可以看出,ArrayList想要get(int index)元素时,直接返回index位置上的元素,而LinkedList需要通过for循环进行查找,虽然LinkedList已经在查找方法上做了优化,比如index < size / 2,则从左边开始查找,反之从右边开始查找,但是还是比ArrayList要慢。这点是毋庸置疑的。
  • ArrayList想要在指定位置插入或删除元素时,主要耗时的是System.arraycopy动作,会移动index后面所有的元素;LinkedList主耗时的是要先通过for循环找到index,然后直接插入或删除。这就导致了两者并非一定谁快谁慢

 3. 空间复杂度

在LinkedList中有一个私有的内部类,定义如下:

private static class Entry {
         Object element;
         Entry next;
         Entry previous;
     }

  • 如果有1000个元素的LinkedList对象将有1000个链接在一起的Entry对象,每个对象都对应于列表中的一个元素。这样的话,在一个LinkedList结构中将有一个很大的空间开销,因为它要存储这1000个Entity对象的相关信息。
  • ArrayList使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间

ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间

实际开发中怎么选择?

1、如果你十分确定你插入、删除的元素是在前半段,使用LinkedList
2、如果你十分确定你删除、删除的元素后半段,使用ArrayList
3、如果你上面的两点不确定,建议你使用LinkedList

说明:
1)、LinkedList整体插入、删除的执行效率比较稳定,没有ArrayList这种越往后越快的情况;
2)、插入元素的时候,弄得不好ArrayList就要进行一次扩容,而ArrayList底层数组扩容是一个既消耗时间又消耗空间的操作,所以综合来看就知道选择哪个类型的list


http://www.kler.cn/a/7591.html

相关文章:

  • 后端——接口文档(API)
  • 坚果云·无法连接服务器(无法同步)
  • Unity音频导入设置
  • 相机光学(四十四)——ALL-PD和PDAF
  • SpringCloud-使用FFmpeg对视频压缩处理
  • Mac解压包安装MongoDB8并设置launchd自启动
  • minikube apiserver无法启动问题解决
  • C++并发与多线程笔记八:async、future、packaged_task、promise
  • 刷题记录|Day48 ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III
  • arm系列交叉编译器各版本区别
  • 如何选择理想的三相浪涌保护器?
  • 【Ruby学习笔记】13.Ruby 迭代器及文件的输入与输出
  • 【vSphere | Python】vSphere Automation SDK for Python Ⅲ—— vCenter Datacenter APIs
  • 为什么无法跨centos、ubuntu、rocky linux 发行版本进行系统升级?
  • xinput1_3.dll缺失了如何去修复?xinput1_3.dll解决方法分享
  • 释放AIoT商业价值 | 2023高通广和通智能物联网技术开放日圆满落幕
  • srs流媒体录制视频
  • 22.SSM-JdbcTemplate总结
  • 贯穿设计模式第二话--开闭职责原则
  • 区块链学习笔记(3)BTC协议
  • 运算符重载
  • 亚马逊管理的14条领导力准则
  • C/C++协程编程:解锁并发编程新纪元
  • 【MySQL】了解MySQL的Explain,读这一篇够了( ̄∇ ̄)/
  • 【刷题笔记】笔记三
  • cuda学习4-6