一个面试问题,我无法回答,也无法在线找到任何相关答案。
假设一个数组列表中有10000个数据,我想找到当前位于第5000个索引上的数字,数组列表如何知道这些索引并在恒定时间内给出结果?
因为如果我们遍历数组列表以查找数据,则将花费线性时间而不是恒定时间。
谢谢。
答案 0 :(得分:4)
支持ArrayList
的存储是一个数组。无论是存储原始值还是对象引用,数组中的所有对象在内存中都是连续的顺序。
对于数组访问,编译器所需要做的就是根据初始地址和所需索引(即O(1))计算正确的内存地址的指令。然后,它可以直接转到该计算出的地址。没有遍历,因此不是O(n)。
答案 1 :(得分:2)
ArrayList
在引擎盖下使用了 array ,即名称。数组是具有直接,快速,基于索引的访问的数据结构。
因此,如果您要求索引为5 000
的元素,则它只会询问其内部数组:
// More or less
return array[5000];
这是OpenJDK 8中的完整方法:
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
尤其是,它不会不遍历到该点的所有元素。这就是其他没有基于索引的访问的数据结构所需要做的。如LinkedList
。请注意,存在一个指示符界面,称为RandomAccess
(documentation)。实现该接口的类具有基于索引的直接访问。当前的实现是:
ArrayList, AttributeList, CopyOnWriteArrayList,
RoleList, RoleUnresolvedList, Stack, Vector
那么,数组如何直接访问该元素?好吧,数组的大小是固定的。创建它时,需要告诉它大小。例如10 000
:
Foo[] array = new Foo[10000];
您的计算机将为10 000
的{{1}}个对象分配连续内存。关键是存储区域是连续,而不是分散分布。因此,第三个元素紧随第二个元素之后,紧接在您的记忆中第四个元素之前。
当您现在要在位置Foo
上检索元素时,计算机将在以下存储位置处检索5 000
对象:
Foo
众所周知,自从声明数组以来,计算速度很快,显然是在恒定时间startAddressOfArray + 5000 * sizeOfFoo
中进行的。因此,数组可以直接基于索引访问其元素。因为这些东西存储在一起,所以连续地存储在内存中。
您可能会在Wikipedia上阅读有关数组的更多信息。
这是techcrashcourse.com的图片,显示了一个数组,其中包含每个元素的地址:
该数组的大小为O(1)
,并存储使用7
个字节(2
位)的整数。通常称为16
,所以称为short
数组。您可以看到每个元素与其上一个元素偏移new short[7]
个字节(2
的大小)。如图所示,这样可以通过简单的计算直接访问给定位置的元素。
答案 2 :(得分:1)
ArrayLists可以看作是一个对象数组(恰好正是它们的实现方式)。您可以像在O(1)上的任何其他数组一样对其进行索引。与真正的“数组”相比,它的优势在于,它可以跟踪“长度”,而与数组的长度无关,并在“溢出”时自动扩展数组,并执行一些额外的操作。
LinkedLists(可能是您正在考虑的结构)要求您从一个项目移到另一个项目,因此实现是O(n)在索引处查找项目。
答案 3 :(得分:0)
顾名思义,short
将元素存储在数组中。这是oracle JDK中的相关代码:
ArrayList
因此,/**
* 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
仅获得内部数组中的第n个元素,就不足为奇了:
list.get(index)