ArrayList获取操作O(1)。怎么样?

时间:2013-09-25 17:46:55

标签: java big-o

在其中一个stack overflow answers中,为什么ArrayList.get是O(1)而不是O(n)

响应者说ArrayList由数组和

支持
      RangeCheck(index); 

决定了恒定时间复杂度而不是线性!我试图绕过这个,不会任何数组必须至少部分搜索一个数组中n个字段的%年龄因此构成O(n)搜索(如果该元素被搜索为在数组的n-1位置 - 这不是一个O(n)搜索吗?它仍然是一个循环的级别,我认为是O(n)复杂度?

3 个答案:

答案 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)方法是直接数组访问的瘦包装器,因此它也受常量限制。