在其中一个stack overflow answers中,为什么ArrayList.get是O(1)而不是O(n)
响应者说ArrayList由数组和
支持 RangeCheck(index);
决定了恒定时间复杂度而不是线性!我试图绕过这个,不会任何数组必须至少部分搜索一个数组中n个字段的%年龄因此构成O(n)搜索(如果该元素被搜索为在数组的n-1位置 - 这不是一个O(n)搜索吗?它仍然是一个循环的级别,我认为是O(n)复杂度?
答案 0 :(得分:17)
数组按顺序放在内存中。这意味着,如果它是一个整数数组,每个使用4个字节,并从内存地址1000开始,则下一个元素将是1004,接下来是1008,依此类推。因此,如果我想在我的数组中的第20位元素,get()
中的代码将必须计算:
1000 + 20 * 4 = 1080
获得元素的确切内存地址。那么,RAM内存的名称是随机访问内存,因为它们的构建方式使得它们具有硬件多路复用器的层次结构,允许它们在恒定时间内访问任何存储的内存单元(字节?),给出了地址。
因此,两个简单的算术运算和一个对RAM的访问被称为O(1)。
答案 1 :(得分:14)
按照建议发布答案:
ArrayList.get(int)
不会搜索。它直接返回由提供的索引寻址的元素......与数组完全相同 - 因此名称。
ArrayList.get(int)source:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
rangeCheck(int)是:
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
而elementData()是:
E elementData(int index) {
return (E) elementData[index];
}
链接列表会有O(n)
获取:它必须步入下一个元素,直到达到所需的索引...
public E get(int index) {
return entry(index).element;
}
entry(int)是(这就是O(n)的原因):
private Entry<E> More ...entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
Entry<E> e = header;
if (index < (size >> 1)) {
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
(注意:它是双链表,因此通过选择最接近所需结果的终点节省一些时间,但这仍然是O(n))
答案 2 :(得分:0)
访问数组中的特定索引是一个常量时间操作,因为它涉及从数组对象获取基本内存地址,并在基址+索引乘以元素类型的大小访问内存。由于跳过了中间的所有元素,因此访问时间受常量限制。
ArrayList.get(int)
方法是直接数组访问的瘦包装器,因此它也受常量限制。