【问题标题】:Add element in an ArrayList efficiently at a given index in java在java中的给定索引处有效地在ArrayList中添加元素
【发布时间】:2013-06-13 07:44:01
【问题描述】:

我需要在索引 i 处的 ArrayList 中插入 Person 类型的元素(我自己定义的类)

我知道我可以使用add(int index, E element)

但是有没有任何有效的方法可以做到这一点,因为在我的列表中平均需要大约 1.5 毫秒(收集超过 1000 次插入的数据,然后平均)。

【问题讨论】:

  • 你的名单有多大?如果您提前将数据插入到一个非常大的列表中,您将复制大量数据...
  • 你的意思是 - 有没有更高效的插入列表实现?
  • 如果有更有效的方法使用 ArrayList,我会感到惊讶。核心功能应该优化得很好。另外,您认为 1.5 毫秒慢吗?
  • LinkedListArrayList 更适合在列表中插入/删除。
  • 列表中已经有超过 100,00 个元素,我每 20 毫秒添加 1 个元素。 1.5 毫秒是平均的,根据我的要求,它很慢。我需要在特定索引处插入,所以我猜 arraylist 会好得多,因为它给出了大约 0.02 - 0.1 ms 的数组(我知道数组列表需要扩展,但仍然)

标签: java performance arraylist


【解决方案1】:

如果您的任务是更密集的插入/删除,您可以随时使用java.util.LinkedList

  • ArrayList 的大小有限。每次添加元素时,Java 都会确保它能够适应 - 因此它会增长 ArrayList。如果 ArrayList 增长得更快,就会发生大量的数组复制。
  • LinkedList 只是将元素添加到正确的位置(链接周围的节点),而不需要增长和复制整个 ArrayList。
  • LinkedList 的缺点是在您搜索元素时。由于它没有索引,它必须从列表的开头遍历到结尾才能找到一个项目。

对于LinkedList

  • 得到是 O(n)
  • 加起来是 O(1)
  • 删除是 O(n)
  • Iterator.remove 是 O(1)

对于ArrayList

  • 得到是 O(1)
  • add 摊销为 O(1),但最坏情况为 O(n),因为必须调整和复制数组的大小
  • 删除是 O(n)

【讨论】:

  • 我需要先进行二进制搜索以找到索引然后需要插入,我不能使用 Linkedlist,因为我正在做的是插入使用 arraylist 作为底层模型的 tableview(ObservableList ).
  • 您能更具体地介绍一下 TableView 吗?
  • 这是answer 的副本(更详细)
  • @GuillaumePolet +1 在提问之前我已经检查了该答案
【解决方案2】:

如果你添加使用

arryListInstance.add(positionIndex, Object);

将现有对象筛选 1 个位置后添加对象。因此这个操作的平均情况变成O(n)

虽然简单的添加

arryListInstance.add(positionIndex, Object);

在arrayListInstance 的末尾添加对象。在最好的情况下,这个操作是 O(1),但在最坏的情况下,当达到最大容量时它变成 O(n):因为一个新的 ArrayList 实例是内部创建,所有内容都复制到那里。

您面临这个问题是因为可以避免第一个原因的两个原因之一:

  1. 您没有为 ArrayList 对象定义足够的初始容量。因此,在每个 arrayListInstance.add(positionIndex, object) 之前,正在创建一个增加容量的 new arrayListInstance,然后复制原始列表中的现有元素,然后最后添加 正在执行。如果您确切知道要通过此列表处理多少数据并相应地定义初始容量(与可能的元素数量相同),则可以避免这种情况。如果您无法预测初始容量,那么最好按批量处理数据。
  2. 在除最后一个位置之外的任何位置每次插入后都会筛选现有元素。这是不可避免的。因此,如果 positionIndex 不是 arrayList 的最后一个索引,arrayListInstance.add(positionIndex, object) 将在 O(n) 时间内执行.即使您使用 LinkedList,您也无法实现恒定时间添加操作,该操作将元素添加到列表中除最后一个元素之外的索引处。

【讨论】:

  • 您在两种情况下都使用相同的添加,因此投反对票。第二个添加不是“简单”添加。
  • 应该是arryListInstance.add(Object);
【解决方案3】:

这种插​​入发生在 O(n) 中,因为它必须向下移动所有元素,最坏的情况是它会将每个元素向下移动。 (更正的java说它是O(n),因为他们使用数学公式来插入)

如果你想要快速插入,要么将它添加到数组列表的末尾,要么使用一个恒定时间的哈希图。

插入哈希表: HashMap peopleMap = new Hashmap.....

peopleMap.put(person.name, person); //(或任何你想跟踪的)

这会将键设置为人员姓名,并将值设置为人员。

您还可以尝试使用带有键的哈希图(例如您要跟踪的任何人)并评估人员在持有人数组中的索引。插入是 O(i),查找 O(i) 并且您也可以对其进行排序(我将把这个作为练习留给读者)

如果这样做的全部目的是排序,那么为简单起见,您可以插入一个 priorityQueue (nLogn),然后将所有内容弹出到数组中,这将为您提供一个排序后的数组

【讨论】:

  • 怎么可能是 O(n^2) 我需要移动完整的数组,我将从头开始。我想这就是 System.arraycopy 的工作方式,而且速度非常快
  • put(index, value); 其中索引是键
  • @waf 但这实际上取决于实现方式,如果您所说的始终正确,那么插入排序将是 O(n^3) 不是吗?
  • 只需阅读 Java 的实现细节,由于它们用于插入的一些公式,它是 O(n)
猜你喜欢
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 1970-01-01
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
相关资源
最近更新 更多