英文:
Is get(0) on java.util.List always O(1)?
问题
根据我的知识,以下是已实现的内容:
- ArrayList
- LinkedList
- Vector
- Stack
(基于 http://tutorials.jenkov.com/java-collections/list.html 如果有错误请纠正)
ArrayList 是动态数组实现,因此像数组一样,获取操作为 O(1);LinkedList 从头部获取为 O(1);Vector 和 Stack 基于 ArrayList,因此也为 O(1)。
所以,在任何内置实现(因为你可以自己创建,针对特定目的进行 get(0) 操作的 O(n!) 实现)的列表中,对于 get(0) 操作都是 O(1) 吗?
英文:
Of my knowledge, there are the following implementations:
- ArrayList
- LinkedList
- Vector
- Stack
(based on http://tutorials.jenkov.com/java-collections/list.html pls correct if wrong)
ArrayList is a dynamic array implementation, so, as array, get is O(1), LinkedList has O(1) for get from Head, Vector and Stack are based on ArrayList, hence, O(1).
So in EVERY case get(0) on any built-in (cause you can make your own, for a specific purpose on making get(0) TS of O(n!)) implementation of List if O(1)?
答案1
得分: 3
> 在 java.util.List 上调用 get(0) 是否总是 O(1)?
假设存在一个参数 N
代表列表的长度<sup>1</sup>。
对于你提到的那四种 List
实现,get(0)
确实是一个 O(1)
的操作:
-
ArrayList
、Vector
和Stack
都是通过数组下标来实现get(i)
,这是一个O(1)
的操作。 -
LinkedList.get(i)
需要进行i
次链表遍历,所以是O(i)
。但如果i
是一个常数,那么复杂度就降低为O(1)
。
然而,还有其他“内置的”List
实现。事实上,如果考虑各种非公开的实现,比如实现子列表、不可修改列表等,那么实现的数量相当可观。从那四种实现泛化到“所有的实现”是不准确的<sup>2</sup>。
但是,并不是所有可能的 List
实现中 get(0)
都是 O(1)
。
-
考虑一个简单的链表,其中元素按相反的顺序链接。因为
get(0)
需要遍历到链表的末尾,需要N
次链表遍历,复杂度为O(N)
。 -
考虑一个列表,第一次尝试检索列表元素时,它从数据库查询结果集的行中完全填充。第一次
get
调用至少是O(N)
,因为你要获取N
行。(如果数据库查询不是O(N)
,那么情况可能更糟。)因此,对于任何get
调用的最坏情况复杂度都是O(N)
……或者更糟。
实际上,通过一些巧妙的方法,可以发明一个自定义列表,其中 get(0)
的 Big-O 复杂度可以是任何你提出的。
<sup>1 - 我在这里故意含糊其辞。一方面,我们需要确定一个变量 N
,表示复杂性分析的“问题”大小。(列表的长度是显而易见的选择。)另一方面,当考虑所有可能的接口实现方式时,List
的长度是一个令人惊讶且“有弹性”的概念。</sup>
<sup>2 - 我假设你之所以问这个问题,是因为你想编写一些依赖于 List.get(0)
为 O(1)
的库代码。由于无法阻止其他人使用非内置的列表实现来使用你的库,所以你问题中的“假设它是内置的”限制实际上没有帮助……即使我们可以检查所有可能的(过去、现在或未来的)内置 List
实现。</sup>
英文:
> Is get(0) on java.util.List always O(1)?
Let us assume that there is a parameter N
which stands for the length of the list<sup>1</sup>.
For the 4 implementations of List
that you mentioned, get(0)
is indeed an O(1)
operation:
-
ArrayList
,Vector
andStack
all implementget(i)
using array subscripting and that is anO(1)
operation. -
LinkedList.get(i)
involvesi
link traversals which isO(i)
. But ifi
is a constant, that reduces toO(1)
.
However there are other "built in" implementations of List
. Indeed, there are a considerable number of them if you include the various non-public implementations, such as the List
classes that implement sublists, unmodifiable lists, and so on. Generalizing from those 4 to "all of them" is not sound<sup>2</sup>.
But get(0)
won't be O(1)
for all possible implementations of List
.
-
Consider a simple linked list where the elements are chained in the reverse order. Since
get(0)
needs to traverse to the end of the list, which isN
link traversals:O(N)
. -
Consider a list that is fully populated from the rows in a database query's result set the first time that you attempt to retrieve a list element. The first
get
call will be at leastO(N)
because you are fetchingN
rows. (It could be worse thanO(N)
if the database query is notO(N)
.) So the worst case complexity for any call toget
isO(N)
... or worse.
Indeed, with a some ingenuity, one could invent a custom list where get(0)
has any Big-O complexity that you care to propose.
<sup>1 - I am being deliberately vague here. On the one hand, we need to identify a variable N
denoting the "problem" size for complexity analysis to make sense. (The length of the list is the obvious choice.) On the other hand, the length of a List
is a surprisingly "rubbery" concept when you consider all of the possible ways to implement the interface.</sup>
<sup>2 - I assume that you are asking this question because you want to write some library code that relies on List.get(0)
being O(1)
. Since you can't prevent someone from using your library with a non-builtin list implementation, your "assume it is builtin" constraint in your question doesn't really help ... even if we could check all possible (past, current or future) builtin List
implementations for you.</sup>
答案2
得分: 0
忽略自定义实现,仅考虑内置实现,就像问题末尾建议的那样,你仍然不能断言无论列表大小如何,get(0)
都是 O(1)。
举个例子,在基于 LinkedList
的子列表上调用 get(0)
将是 O(n):
List<Integer> list = new LinkedList<>(Arrays.asList(1,2,3,4,5,6,7,8,9));
List<Integer> subList = list.subList(4, 8);
Integer num = subList.get(0); // <===== O(n),不是 O(1)
在这段代码中,subList.get(0)
在内部调用了 list.get(4)
,其时间复杂度为 O(n)。
英文:
Ignoring custom implementations, and only looking at built-in implementations, like suggested at the end of the question, you still cannot say that get(0)
will be O(1) regardless of list size.
As an example, calling get(0)
on a sublist based on a LinkedList
will be O(n):
List<Integer> list = new LinkedList<>(Arrays.asList(1,2,3,4,5,6,7,8,9));
List<Integer> subList = list.subList(4, 8);
Integer num = subList.get(0); // <===== O(n), not O(1)
In that code, subList.get(0)
internally calls list.get(4)
, which has O(n) time complexity.
答案3
得分: -2
是的,对于您提到的所有List
的实现,get(0)
的时间复杂度是O(1)。
英文:
Yes, for all implementations of List
you mentioned get(0)
is O(1).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论