使用此Java代码:
// create the items list
List<Item> items = new ArrayList<Item>();
// ... (add some elements into the list so that it is not empty)
// iterating ArrayList<Item> from right to left we find the position
// based on the `if` condition satisfied for an item property
int pos = 0;
for (int j = items.size() - 1; j >= 0; j--) {
Item item = items.get(j);
if (item.property <= 7) {
pos = j + 1; break;
}
}
// add new item on the found above position
Item it = new Item();
if (pos == items.size()) {
items.add(it);
} else {
items.add(pos, it);
}
如果由于使用了Item item = items.get(j);
,此语句ArrayList
将需要一些额外的时间来执行,我正在讨论。例如,假设我们需要将新项添加到最后,然后通过在项列表上调用get()
将仅从左侧迭代它,这是多余的。我希望使用Deque
结构而不是ArrayList
。
你能推荐什么,也许我完全错了,因为新元素也可以在开头添加,但目标是从右侧向左侧迭代。
答案 0 :(得分:9)
Get
以恒定时间运行。证明:javadoc。
运行size,isEmpty,get,set,iterator和listIterator操作 在不断的时间。
所以不要担心get
表现。 ArrayList
不是链接列表。我认为它是由普通的java数组支持的。
答案 1 :(得分:1)
对于ArrayList
,操作get(i)
,迭代和(右)端的添加/删除都很便宜(基本上是O(1)或摊销的O(1))。但是,在另一端(左)添加/删除元素非常昂贵,并且每次都要复制整个后备阵列。
因此,如果您需要在两端添加和删除,请务必使用ArrayDeque
。对于所有操作,这基本上与ArrayList
一样便宜,但支持以便宜的方式在两端添加。
请注意,如果您只想在列表的开头添加/删除,而不是在结尾处,您仍然可以使用ArrayList
而只是“向后”(所以当您想要添加内容时)一开始,你只需在最后添加它,当你想从右向左迭代时,你实际上是从左到右迭代。)
对于两个数据结构,使用add(Object, int)
方法插入元素为O(n)(插入元素右侧的所有元素都需要在数组中移动)。
另一种方法是使用LinkedList
(也实现Deque
)。您只需要确保不使用get(int)
或将索引作为int传递的任何其他方法,因为这是O(n)。但是,添加/删除/插入操作在列表中的所有位置都是O(1)(只要您已经有一个指向该位置的迭代器)。因此,对于代码中的循环,请在列表中调用.listIterator()
,进行适当迭代并使用ListIterator.add(Object)
方法插入元素。这对您的代码来说是最便宜的解决方案。
修改强> 的
我没有注意到ArrayDeque
没有提供在中间插入元素的方法(尽管它可以像ArrayList
一样)。 (感谢A.H.)因此,如果您确实需要所有这些操作(在开头,中间和结尾插入),请使用LinkedList
和ListIterator
。
答案 2 :(得分:0)
不,可能不是。你的for循环从右到左迭代,如果可能是最快的实现。
如果您使用的是LinkedList,那么答案是肯定的 - 您应该使用listIterator()向后迭代,因为LinkedList上的.get(i)很慢。 ArrayList也有listIterator(),但使用它和一个简单的for循环向后迭代之间可能没有什么不同。
如果你真的关心每一个ms,你应该把你在互联网上阅读的这个问题和基准测试中的所有内容用一小撮盐进行,并运行大量的负载测试并用VisualVM进行大量的分析,告诉你在哪里系统中真正的性能瓶颈是。