【问题标题】:ArrayList vs Array and ListArrayList vs 数组和列表
【发布时间】:2015-10-24 17:55:45
【问题描述】:

我已经编程了很长时间,最近开始学习更纯的计算机科学主题(用于工作面试)。

我知道 Array 和 LinkedList 数据结构之间的区别,但现在我已经开始使用 Java,我看到了这个 ArrayList,我在概念化时遇到了麻烦。

网络搜索只真正向我展示了如何使用它们以及何时使用它们(每种方法的好处),但没有什么可以回答我的问题:

什么是数组列表?我的假设是它是一个维护每个元素的内存引用的列表,使其也能够像数组一样工作。

我也有一种感觉,因为 Java 是开放的,我应该可以查看 Class 定义,但我还没有弄清楚如何做到这一点。

谢谢!

【问题讨论】:

  • 您尝试过 Google ArrayList 吗?
  • 是的,我只得到了关于如何使用它、何时使用它以及方法/属性是什么的结果。我想知道底层数据结构是什么样的。它是一个数组还是一个列表,或者两者兼而有之。
  • 按逻辑,我假设 ArrayList 是 List 的更具体版本。它的结构是一个 List,但它的方法类似于 Array 的方法。
  • 您可以在 IDE 中查看 ArrayList 源代码(在 IntelliJ 中,在代码中选择 ArrayList,然后 CTRL + 鼠标左键单击)。您会看到ArrayList 本质上是一个包装好的Object[],其中包含许多方便的插入、删除等方法。
  • 谢谢@pbabcdefp!这就是我要找的东西!

标签: java arrays arraylist data-structures linked-list


【解决方案1】:

我喜欢将其视为一种数据结构,让您享受两全其美的体验,即快速访问索引(如数组)和无限增长的列表。当然,总会有取舍。

ArrayList 实际上是一个数组的包装器。每次数组大小结束时,都会创建一个大小为两倍的新数组,并将原始数组中的所有数据复制到新数组中。

来自 java 文档:

List 接口的可调整大小的数组实现。实现所有 可选列表操作,并允许所有元素,包括 null。在 该类除了实现 List 接口外,还提供 操作内部使用的数组大小的方法 存储列表。 (这个类大致相当于Vector,除了 大小、isEmpty、get、set、iterator 和 listIterator 操作在恒定时间内运行添加操作运行 在摊销常数时间内,即添加 n 个元素需要 O(n) 时间。所有其他操作都以线性时间运行(大约 请讲)。常数因子低于 链表实现。

每个 ArrayList 实例都有一个容量。容量是大小 用于存储列表中元素的数组。它总是在 至少与列表大小一样大。随着元素被添加到 ArrayList,它的容量会自动增长。成长的细节 除了添加元素具有 固定摊销时间成本。

应用程序可以增加 ArrayList 实例的容量 在使用 ensureCapacity 添加大量元素之前 手术。这可能会减少增量重新分配的数量。

这允许 O(1) 访问大多数操作,就像使用数组一样。有时,您需要为这种性能付出代价,但插入操作需要更长的时间。

这称为amortized 复杂性。每个操作只需要 O(1),因为您需要将数组大小加倍。在那些时候你会支付 O(n) 但如果你在 n 次操作中平均它,平均花费的时间只有 O(1) 而不是 O( n).

举个例子:

我们有一个大小为 100 (n=100) 的数组。您进行了 100 次插入操作(针对不同的索引),每个操作只需要 O(1),当然所有按索引获取的操作也需要 O(1) > (因为这是一个数组)。在 101 插入时,数组中没有更多容量,因此 ArrayList 将创建一个大小为 200 的新数组,将所有值复制到其中(O(n) 操作)然后插入第 101 项。在您将数组填充到 200 个项目之前,所有操作都需要 O(1)

【讨论】:

  • 谢谢!!我以前没有听说过摊销分析。不过,这是有道理的。似乎在时间复杂度中使用它是有意义的,但在空间中你不会经常以 O(2n) 结束吗?这是否只是假设对象不是很大并且设备可以处理它?我想这些书所经历的理论多于实践。我不打算在我的移动应用程序中使用 10^20 个元素,而计算机科学书籍则避免使用 2 倍内存。
  • 在复杂度分析中,O(2n) 与 O(n) 相同。如果你在谈论 Android 应用程序,你不应该担心 ArrayList 的开销内存,你很可能有足够的空间。除非您要创建数十亿个对象。
  • 这是有道理的。再次感谢!有点离题,但是 O(n) 是发音(就像在采访中一样)“n 的大哦”还是其他方式?
  • 我想你会说 Oh-En。但我不是以英语为母语的人,所以我真的不确定:)
【解决方案2】:

ArrayList 是一个直接由数组支持的列表。更具体地说,它由一个动态调整大小的数组支持。您可以在its source code 中阅读更多相关信息;有一些相当不错的 cmets。

这很重要的原因是LinkedList 是如何实现的——作为传统的节点集合和对其他节点的引用。这会影响索引和遍历的性能,而对于 ArrayList,由于它由数组支持,因此只需对特定数组进行索引即可检索值。

【讨论】:

  • 那么,如果它由数组支持,这是否意味着添加/插入/删除问题标签代价高昂,或者它是否以某种方式进行了优化?我想动态数组是我要研究的下一个主题!谢谢!
  • 取决于你的能力。调整数组大小时可能会产生 O(n) 成本(如果容量不足或接近阈值),但如果您处于中间位置,则成本为 O(1)。删除将是 O(n-i),因为您必须将剩余值移到左侧以填充缺失值。
  • 在数组的末尾插入新元素的摊销成本是恒定的,移除它们也是如此。但是,如果您从数组中间插入/删除元素,您将支付线性成本,因为您必须平均移动 n / 2 个元素。
  • 谢谢!!我喜欢这样解释每种方法。
  • 是的 - 它是 Javadoc,它来自同一来源 that the API is using。这显示了内联 cmets,因为它们对实现细节有更多的建议。
猜你喜欢
  • 2014-03-20
  • 2010-12-26
  • 1970-01-01
  • 2020-07-25
  • 2011-08-05
  • 2012-11-29
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多