Arrays 访问元素-真的是O(1)?

Arrays 访问元素-真的是O(1)?,arrays,algorithm,big-o,computer-science,asymptotic-complexity,Arrays,Algorithm,Big O,Computer Science,Asymptotic Complexity,O(1)操作的一个例子是访问数组中的元素。根据一种方法,O(1)可以以下列方式定义: [Big-O of 1]表示算法的执行时间不依赖于 输入的大小。它的执行时间是恒定的 但是,如果要访问数组中的元素,操作的效率不取决于数组中元素的数量吗?比如说 int[] arr = new int[1000000]; addElements(arr, 1000000); //A function which adds 1 million arbitrary integers to the array.

O(1)操作的一个例子是访问数组中的元素。根据一种方法,O(1)可以以下列方式定义:

[Big-O of 1]表示算法的执行时间不依赖于 输入的大小。它的执行时间是恒定的

但是,如果要访问数组中的元素,操作的效率不取决于数组中元素的数量吗?比如说

int[] arr = new int[1000000];
addElements(arr, 1000000); //A function which adds 1 million arbitrary integers to the array. 

int foo = arr[55]; 
我不明白最后一个语句如何被描述为在O(1)中运行;数组中的1000000个元素对操作的运行时间没有影响吗?找到元素55肯定要比找到元素1花费更长的时间?如果有什么区别的话,我觉得这就像O(n)


我确信我的推理是有缺陷的,但是,我只是想澄清一下,这可以说是如何在O(1)中运行的?

内存中元素的地址将是数组的基址加上索引乘以数组中元素的大小。因此,要访问该元素,您只需访问
内存位置+55*sizeof(int)


当然,这是假设无论输入的大小,乘法都需要恒定的时间,如果数组是一个数据结构,其中对象存储在连续的内存位置,这可能是不正确的。因此,原则上,如果您知道基本对象的地址,您将能够找到
ith
对象的地址

addr(a[i])=addr(a[0])+i*大小(对象)

这使得访问数组O(1)的第i个元素成为可能

编辑
理论上,当我们谈论访问数组元素的复杂性时,我们谈论的是固定索引
i

输入大小=O(n)
要访问第i个
element,
addr(a[0])+i*size(object)
。这个术语独立于
n
,因此被称为O(1)


如何乘法仍然取决于
i
,而不是
n
。它是常数O(1)。

查找元素不是O(1)-但是访问数组中的元素与查找元素无关-准确地说,您不与其他元素交互,您不需要访问任何东西,只需要访问单个元素-您总是计算地址,不管数组有多大,这是一个操作,因此是O(1)。

如果我们说下标操作符(索引)有O(1)时间复杂度,我们做这个语句,不包括任何其他操作/语句/表达式等的运行时。因此,
加法不影响操作

找到元素55肯定要比找到元素1花费更长的时间

“找到”?哦,不!“查找”意味着一个相对复杂的搜索操作。我们知道数组的基址。为了确定
arr[55]
处的值,我们只需将
55
1添加到基址并检索该内存位置处的值。这绝对是O(1)



1由于
int
数组的每个元素都至少占用两个字节(使用C时),因此这并不完全正确
55
首先需要乘以
int
的大小。

数组连续存储数据,这与链表、树、图或其他使用引用查找下一个/上一个元素的数据结构不同

您可以直观地看到,第一个元素的访问时间是O(1)。然而,您觉得第55个元素的访问时间是O(55)。这就是你弄错的地方。您知道第一个元素的地址,所以对它的访问时间是O(1)

但你也知道第55元素的地址。它只是第一个地址+每个元素的大小*54

因此,您可以在O(1)时间内访问该元素以及数组的任何其他元素。这就是为什么在一个数组中不能有多种类型的元素,因为这将彻底打乱寻找数组第n个元素地址的数学过程


因此,对数组中任何元素的访问都是O(1),所有元素都必须是同一类型。

理论上,数组访问是O(1),正如其他人已经解释过的,我猜你的问题或多或少是一个理论问题。但我还是喜欢引入另一个方面

实际上,如果阵列变大,阵列访问速度会变慢。原因有两个:

  • 缓存:阵列将不适合缓存或仅适合更高级别(较慢)的缓存
  • 地址计算:对于大型数组,需要更大的索引数据类型(例如long而不是int)。这将降低地址计算的速度,至少在大多数平台上是如此
为语句生成的机器代码(或者,对于Java,是虚拟机代码)

int foo = arr[55];
基本上是:

  • 将arr的起始内存地址获取到
  • 将55添加到
  • 取A中内存地址的内容,并将其放入foo的内存地址中

  • 这三条指令在标准机器上都需要O(1)个时间

    O(55)和O(1)不一样吗?@FrankPuffer:是的,但是当你取一个普通的n而不是具体的55时,它就变成了O(n)。接受,但你的回答可能会给人一种错误的印象,认为有区别。@FrankPuffer:我认为不应该。我从问题中拿了这个例子。任何完全阅读这个问题的人都不会感到困惑。此外,这个评论线程将消除任何进一步的怀疑。理论上,你不能假设乘法需要恒定的时间。但在我们的例子中,因为它涉及的数字与输入大小无关,所以我们认为它是常数。对,在“访问
    ith
    索引”的上下文中,这是最准确的答案。假设内存是使用以恒定位大小表示的数字来寻址的。大O表示法描述了限制行为,是一个相当理论化的概念,其中内存(磁带)是无限的和线性的——因此一般的“访问”操作应该是g