4

我正在研究一种算法,它将一小部分对象存储为一大组对象的子列表。对象本质上是有序的,因此需要一个有序列表。

执行的最常见操作将按频率顺序排列:

  1. 从列表中检索第 n 个元素(对于一些任意 n)
  2. 在列表的开头或结尾插入一个
  3. 从列表中删除第一个或最后一个 n 元素(对于一些任意 n)

从中间删除和插入永远不会完成,因此无需考虑其效率。

我的问题是,对于 Java 中的这个用例(即 LinkedList、ArrayList、Vector 等),List 的哪种实现最有效?请通过解释不同数据结构的实现来捍卫您的答案,以便我做出明智的决定。

谢谢。

笔记

不,这不是作业问题。不,我没有可以为我做这项工作的军队研究助理。

4

6 回答 6

5

根据您的第一个标准(任意访问),您应该使用 ArrayList。ArrayLists(和一般的数组)在恒定时间内提供查找/检索。相反,在 LinkedList 中查找项目需要线性时间。

对于 ArrayLists,末尾的插入或删除是免费的。它也可能与 LinkedLists 一起使用,但这将是特定于实现的优化(否则它是线性的)。

对于 ArrayLists,前面的插入或删除需要线性时间(随着空间的一致重用,这些可能会根据实现变得恒定)。列表前面的 LinkedList 操作是恒定的。

最后两个用例在某种程度上相互平衡,但您最常见的情况肯定建议使用基于阵列的存储。

至于基本的实现细节:ArrayLists 基本上只是内存的顺序部分。如果您知道起点在哪里,则只需进行一次加法即可找到任何元素的位置。前线的操作成本很高,因为可能必须转移元素以腾出空间。

LinkedLists 在内存中是不相交的,由相互链接的节点组成(引用第一个节点)。要找到第 n 个节点,您必须从第一个节点开始并跟随链接,直到到达所需的节点。前面的操作只需要创建一个节点并更新你的开始指针。

于 2012-07-18T18:32:50.573 回答
3

我投票支持双链表。http://docs.oracle.com/javase/6/docs/api/java/util/Deque.html

于 2012-07-18T18:25:01.137 回答
1

用于此目的的最佳数据结构可能是使用动态数组实现的双端队列,它基本上是一个ArrayList开始将元素添加到内部数组的中间而不是开头的元素。不幸的是,JavaArrayDeque不支持查找第 n 个元素。

然而,自己实现一个(或查找现有实现)非常容易,然后所有三个描述的操作都可以在 O(1) 中完成。

于 2012-07-26T22:36:51.797 回答
0

绝对去LinkedList。对于在列表的开头/结尾插入一个值和删除列表中的第一个/最后一个元素,它在 O(1) 中运行。这是因为执行这些操作需要更改的只是几个指针,这是一个成本最低的操作。

虽然 ArrayLists 在 O(1) 中检索第 n 个元素,而 LinkedLists 在 O(n) 中检索第 n 个元素,但 ArrayLists 存在在插入元素时必须调整其大小的危险。当分配给 ArrayList 的内存用完并且您尝试插入另一个元素时,您认为会发生什么?那么发生的事情是 ArrayList 复制自身然后分配更多内存(总计是最初分配的两倍),这是一个非常昂贵的操作。LinkedLists 没有这个问题,因为,再次,所做的只是添加一个指针。

我对 Java 向量了解不多,但如果它们类似于 C++ 向量,那么它们与 ArrayLists 非常相似。

我希望这有帮助。

于 2012-07-18T18:38:31.887 回答
0

如果您不担心效率,您可以使用 arrayList 完成所有这些操作,而不会造成混淆。

如果我只在前端或末端插入,我会使用某种队列或堆栈。他们的开销最小。或者你也可以使用链表。

要从第一个或最后删除 N 个元素,我将使用链表,您只需删除一个节点,然后删除它之前或之后的节点。即,如果我删除前 5 个元素,只需删除第 5 个元素,它之前的元素就会消失。此外,如果我删除最后 6 个元素,只需删除第 6 个到最后一个元素,其余元素就会消失。而java会为你做垃圾收集。对于此操作,这将是 (1) 的顺序。

这是一个家庭作业问题吗?

于 2012-07-18T18:25:29.313 回答
0

java.util.TreeMap 的 Long 到 Object,并使用 i+tm.firstKey() 的索引

于 2016-08-21T15:13:03.940 回答