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

容器——2.Collection 子接口之 List

文章目录

  • 2.1. Arraylist 和 Vector 的区别?
  • 2.2. Arraylist 与 LinkedList 区别?
    • 2.2.1. 补充内容:双向链表和双向循环链表
      • 2.2.2. 补充内容:RandomAccess 接口
  • 2.3 ArrayList 的扩容机制

2.1. Arraylist 和 Vector 的区别?

  • ArrayListList 的主要实现类,底层使用 Object[ ]存储,适用于频繁的查找工作,线程不安全 ;
  • VectorList 的古老实现类,底层使用 Object[ ] 存储,线程安全的。

2.2. Arraylist 与 LinkedList 区别?

  1. 是否保证线程安全: ArrayListLinkedList 都是不同步的,也就是不保证线程安全;
  2. 底层数据结构: Arraylist 底层使用的是 Object 数组LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  3. 插入和删除是否受元素位置的影响:ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度近似为o(n))因为需要先移动到指定位置再插入。
  4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  5. 内存空间占用: ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

2.2.1. 补充内容:双向链表和双向循环链表

双向链表: 包含两个指针,一个 prev 指向前一个节点,一个 next 指向后一个节点。

另外推荐一篇把双向链表讲清楚的文章:https://juejin.im/post/5b5d1a9af265da0f47352f14

在这里插入图片描述
双向循环链表: 最后一个节点的 next 指向 head,而 head 的 prev 指向最后一个节点,构成一个环。

在这里插入图片描述

2.2.2. 补充内容:RandomAccess 接口

public interface RandomAccess {
}

查看源码我们发现实际上 RandomAccess 接口中什么都没有定义。所以,在我看来 RandomAccess 接口不过是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。

binarySearch() 方法中,它要判断传入的 list 是否 RamdomAccess 的实例,如果是,调用indexedBinarySearch()方法,如果不是,那么调用iteratorBinarySearch()方法

public static <T>int binarySearch(List<? extends Comparable<? super T>> list, T key) {if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)return Collections.indexedBinarySearch(list, key);elsereturn Collections.iteratorBinarySearch(list, key);}

ArrayList 实现了 RandomAccess 接口, 而 LinkedList 没有实现。为什么呢?我觉得还是和底层数据结构有关!ArrayList 底层是数组,而 LinkedList 底层是链表。数组天然支持随机访问,时间复杂度为 O(1),所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),所以不支持快速随机访问。,ArrayList 实现了 RandomAccess 接口,就表明了他具有快速随机访问功能。 RandomAccess 接口只是标识,并不是说 ArrayList 实现 RandomAccess 接口才具有快速随机访问功能的!

2.3 ArrayList 的扩容机制

ArrayList 是基于数组实现的动态数组,它提供了一种可以动态增长和缩减的数组结构。在 ArrayList 中,当数组存储的元素个数达到上限时,会触发扩容操作,以保证其容量能够存储更多的元素。

ArrayList 扩容机制的主要过程:

  1. 在添加元素时,首先会判断数组是否已满。如果已满,则需要进行扩容操作;
  2. 扩容操作会创建一个新的大数组,并将原数组中的元素全部复制到新数组中;
  3. 新数组的长度通常是原数组长度的 1.5 倍(可以通过源码中的 DEFAULT_CAPACITY_INCREMENT = 12 和 DEFAULT_CAPACITY = 10 来了解扩容因子)。如果指定了初始化容量,那么新数组的长度就是指定的容量大小;
  4. 复制完元素后,会将指向原数组的引用更新为指向新数组的引用。

源码分析

private void grow(int minCapacity) {// 获取当前数组容量int oldCapacity = elementData.length;// 扩容因子,以 1.5 倍方式进行扩容int newCapacity = oldCapacity + (oldCapacity >> 1);// 如果新容量小于 minCapacity,则使用 minCapacity 作为新容量if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 如果新容量超出了最大容量,则抛出 OutOfMemoryError 异常if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 复制旧数组中的元素到新数组中elementData = Arrays.copyOf(elementData, newCapacity);
}

由于每次扩容都需要重新进行数据复制,所以过于频繁的扩容操作会导致性能损失。为避免频繁的扩容操作,初始化 ArrayList 对象时可以指定其容量大小,或者使用 ensureCapacity(int minCapacity) 方法预先设置其容量大小,以提高效率。同时,在添加大量元素时,也可以使用 addAll(Collection<? extends E> c)addAll(int index, Collection<? extends E> c) 方法,一次性添加多个元素,以减少扩容操作的次数。

http://www.lryc.cn/news/118037.html

相关文章:

  • 【工作记录】docker安装gitlab、重置密码@20230809
  • 数据挖掘的基本概念和大数据的特点
  • LabVIEW开发分段反射器测试台
  • 二级python和二级c哪个简单,二级c语言和二级python
  • E: Package ‘curl‘ has no installation candidate/ E:软件包没有可用的安装源
  • 代理模式及常见的3种代理类型对比
  • 8.6 校招 内推 面经
  • 【大数据之Flume】七、Flume进阶之自定义Sink
  • vue对于时间的处理
  • Apache DolphinScheduler 3.1.8 版本发布,修复 SeaTunnel 相关 Bug
  • 科技云报道:一波未平一波又起?AI大模型再出邪恶攻击工具
  • 深度对话|如何设计合适的网络经济激励措施
  • opencv带GStreamer之Windows编译
  • Java并发编程之锁的升级
  • 多核异构处理器A核与M核通信过程
  • 面试热题(反转链表)
  • 竞赛项目 深度学习的水果识别 opencv python
  • Java项目部署云windows细节
  • 软件功能测试有什么注意事项?功能测试报告起到什么作用?
  • Kubernetes 调度 约束
  • Grafana技术文档-概念-《十分钟扫盲》
  • 【JavaEE进阶】Spring 更简单的读取和存储对象
  • KafKa集群搭建和知识点
  • 剑指 Offer 56 - I. 数组中数字出现的次数题解
  • CSDN付费专栏写作协议
  • [保研/考研机试] KY30 进制转换-大整数转二进制 清华大学复试上机题 C++实现
  • vue3多条件搜索功能
  • C++20协程
  • Zabbix 6.0 监控其他
  • Django rest_framework Serializer中的create、Views中的create/perform_create的区别