Java ArrayList如何在固定时间内检索数据?
一个面试问题我无法回答,也无法在网上找到任何相关答案 假设在一个arraylist中,有10000个数据,我想找到当前在第5000个索引上的数字,arraylist如何知道索引并在固定时间内给出结果 因为如果我们遍历arraylist来查找数据,将需要线性时间,而不是常数时间Java ArrayList如何在固定时间内检索数据?,java,arraylist,Java,Arraylist,一个面试问题我无法回答,也无法在网上找到任何相关答案 假设在一个arraylist中,有10000个数据,我想找到当前在第5000个索引上的数字,arraylist如何知道索引并在固定时间内给出结果 因为如果我们遍历arraylist来查找数据,将需要线性时间,而不是常数时间 提前感谢。可以将ArrayList视为一个对象数组(恰好就是它们的实现方式)。您可以将其作为O(1)处的任何其他数组进行索引。与真正的“数组”相比,它的优势在于它跟踪一个独立于数组长度的“长度”,并在“溢出”时自动扩展数组
提前感谢。可以将ArrayList视为一个对象数组(恰好就是它们的实现方式)。您可以将其作为O(1)处的任何其他数组进行索引。与真正的“数组”相比,它的优势在于它跟踪一个独立于数组长度的“长度”,并在“溢出”时自动扩展数组--再加上一些额外的操作
LinkedList(可能是您正在考虑的结构)要求您从一个项目走到下一个项目,因此实现是O(n)在索引中查找项目。支持
ArrayList的存储是一个数组。无论存储基元值还是对象引用,数组中的所有对象在内存中都是按连续顺序排列的
对于数组访问,编译器所要做的就是根据初始地址和所需的索引计算正确的内存地址,即O(1)。然后它就可以直接转到那个计算出的地址。没有遍历,因此它不是O(n)。ArrayList
ArrayList
在引擎盖下使用一个数组,因此名称为。阵列是具有直接、快速、基于索引的访问的数据结构
因此,如果您要求索引5000
处的元素,它只要求其内部数组:
// More or less
return array[5000];
以下是来自以下网站的完整方法:
特别是,它不会遍历到该点的所有元素。这是其他没有基于索引的访问的数据结构所需要做的。例如LinkedList
。注意,有一个指示器接口,称为RandomAccess
()。实现该接口的类具有直接的基于索引的访问。目前的实施是:
ArrayList, AttributeList, CopyOnWriteArrayList,
RoleList, RoleUnresolvedList, Stack, Vector
数组的工作原理
那么,数组如何直接访问该元素呢?嗯,数组的大小是固定的。创建它时,需要告诉它大小。例如10000
:
Foo[] array = new Foo[10000];
然后,您的计算机将为Foo
的10000
对象分配连续内存。关键是内存区域是连续的,而不是分散的。所以第三个元素直接出现在你记忆中第二个元素之后,第四个元素之前
当您现在要检索位置5000
处的元素时,您的计算机将检索以下内存位置处的Foo
对象:
startAddressOfArray + 5000 * sizeOfFoo
自从声明数组以来,一切都是已知的,计算速度很快,显然是在恒定时间O(1)
中。因此,数组可以直接基于索引访问其元素。因为这些东西是存储在一起的,连续地存储在内存中
您可以在上阅读有关阵列的更多信息
下面是一幅显示每个元素地址的数组的图像:
数组大小为7
,存储使用2
字节(16
位)的整数。通常称为short
,因此是一个新的short[7]
数组。您可以看到,每个元素相对于其上一个元素偏移了2
字节(短的大小)。它可以通过简单的计算直接访问给定位置的元素,如图所示。顾名思义,ArrayList
将元素存储在数组中。以下是oracle JDK中的相关代码:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
因此,毫无疑问,list.get(index)
只获取内部数组中的第n个元素:
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
假设我们不知道元素在第5000个位置,我们只需要搜索一个特定的值(例如正好在第5000个索引上的整数3),为了搜索该值,我们必须遍历arraylist来找到该值,这将需要线性时间,对吗?这不是问题,但是的,它是正确的。在这种情况下,您不会使用arraylist,而是使用hashmap,其中键是整数,值是索引。知道在什么情况下使用什么集合非常重要。问题的关键短语是:“我想找到目前在第5000个索引上的数字”假设我们不知道元素在第5000个位置,我们只需要搜索一个特定的值(例如正好在第5000个索引上的整数3)来搜索值,我们必须遍历arraylist才能找到值,这需要线性时间,对吗???@neil。这不是ArrayList
(或者更一般的列表)的设计目的。通常,您会在O(1)
@ZabuzardstartAddressOfArray+5000*sizeoffo
或startAddressOfArray+5000*sizeOfReference
中使用基于散列的结构,如HashSet
进行基于值的访问?由于Foo
的大小对于Foo
的不同实例可能不同,因此我认为不可能,而是参考大小是固定的,4字节或8字节取决于机器是32位还是64位假设我们不知道元素位于第5000位,我们只需搜索特定的值(例如,正好位于第5000个索引上的整数3),为了搜索值,我们必须遍历arraylist以找到值,这需要线性时间,对吗???@neil无需在每个答案下发布后续内容。您可以对您的问题和@
我们发表评论。或者更好:发布一个新问题,可能将此链接为参考。非常感谢@ZabuzaSuppose we不知道该元素是一个
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}