Accessing Elements - Really O(1)? - arrays

It is said that an example of a O(1) operation is that of accessing an element in an array. According to one source, O(1) can be defined in the following manner:
[Big-O of 1] means that the execution time of the algorithm does not depend on
the size of the input. Its execution time is constant.
However, if one wants to access an element in an array, does not the efficiency of the operation depend on the amount of elements in the array? For example
int[] arr = new int[1000000];
addElements(arr, 1000000); //A function which adds 1 million arbitrary integers to the array.
int foo = arr[55];
I don't understand how the last statement can be described as running in O(1); does not the 1,000,000 elements in the array have a bearing on the running time of the operation? Surely it'd take longer to find element 55 than it would element 1? If anything, this looks to me like O(n).
I'm sure my reasoning is flawed, however, I just wanted some clarification as to how this can be said to run in O(1)?

Array is a data structure, where objects are stored in continuous memory location. So in principle, if you know the address of base object, you will be able to find the address of ith object.
addr(a[i]) = addr(a[0]) + i*size(object)
This makes accessing ith element of array O(1).
EDIT
Theoretically, when we talk about complexity of accessing an array element, we talk for fixed index i.
Input size = O(n)
To access ith element, addr(a[0]) + i*size(object). This term is independent of n, so it is said to be O(1).
How ever multiplication still depends on i but not on n. It is constant O(1).

The address of an element in memory will be the base address of the array plus the index times the size of the element in the array. So to access that element, you just essentially access memory_location + 55 * sizeof(int).
This of course assumes you are under the assumption multiplication takes constant time regardless of size of inputs, which is arguably incorrect if you are being very precise

To find an element isn't O(1) - but accessing element in the array has nothing to do with finding an element - to be precise, you don't interact with other elements, you don't need to access anything but your single element - you just always calculate the address, regardless how big array is, and that is that single operation - hence O(1).

The machine code (or, in the case of Java, virtual machine code) generated for the statement
int foo = arr[55];
Would be essentially:
Get the starting memory address of arr into A
Add 55 to A
Take the contents of the memory address in A, and put it in the memory address of foo
These three instructions all take O(1) time on a standard machine.

In theory, array access is O(1), as others have already explained, and I guess your question is more or less a theoretical one. Still I like to bring in another aspect.
In practice, array access will get slower if the array gets large. There are two reasons:
Caching: The array will not fit into cache or only into a higher level (slower) cache.
Address calculation: For large arrays, you need larger index data types (for example long instead of int). This will make address calculation slower, at least on most platforms.

If we say the subscript operator (indexing) has O(1) time complexity, we make this statement excluding the runtime of any other operations/statements/expressions/etc. So addElements does not affect the operation.
Surely it'd take longer to find element 55 than it would element 1?
"find"? Oh no! "Find" implies a relatively complex search operation. We know the base address of the array. To determine the value at arr[55], we simply add 551 to the base address and retrieve the value at that memory location. This is definitely O(1).
1 Since every element of an int array occupies at least two bytes (when using C), this is no exactly true. 55 needs to be multiplied by the size of int first.

Arrays store the data contiguously, unlike Linked Lists or Trees or Graphs or other data structures using references to find the next/previous element.
It is intuitive to you that the access time of first element is O(1). However you feel that the access time to 55th element is O(55). That's where you got it wrong. You know the address to first element, so the access time to it is O(1).
But you also know the address to 55th element. It is simply address of 1st + size_of_each_element*54 .
Hence you access that element as well as any other element of an array in O(1) time. And that is the reason why you cannot have elements of multiple types in an array because that would completely mess up the math to find the address to nth element of an array.
So, access to any element in an array is O(1) and all elements have to be of same type.

Related

How arrays work in O(1) at the low level?

So it is well known to access an element in an array takes only O(1) time since you can use a simple formula to determine the memory address of the element you want.
For instance, say you have an array starting from address 600 and want the 4th index, where each item in the array takes up 4 bits of space then we can directly access 600 + 4 * 4 = memory address 616.
The question is how? Like at the really low level won't it go "is this address 616? no, it is 600", therefore scans more to the right - "Is this address 616? no, it is 601" etc. Creating a low level O(n) access time.
I suppose my question is, how does the memory instantly access the address it needs to? Thanks for any responses :)

Subtracting a number from all elements of an array in constant time

Can I subtract an integral value from all elements of an array in constant time?
For example:
Given array: 1 2 3 4
Expected array:0 1 2 3
I want this result in O(1) time complexity.Is this possible?
If yes,How can I achieve the same?
P.S.:The expression a[100]={0}; initializes all cells of array to zero without using the for loop.I am looking for similar expression
You can't change n elements in memory in less than O(n) time, but you can change what that memory represents. If you were to create a custom array class you can include an offset member. When an array element is read you add the offset on demand. When an element is added, you subtract the current offset before storing it in memory (so it is recalled as the correct value when added with the offset). With that layout simply modify the offset in O(1) time and effectively achieve what you are looking for.
No. You would need to go through every element and subtract one. Going through every element implies o(n) or linear time. Constant implies you would only need to go through one element.
a[100]={0} is syntactic sugar that appears to be constant but it's actually linear on the backend. See this answer

The Complexity of Locating an Array Element

This is an extremely simple question I nevertheless would like to know the answer to. How does the complexity of locating the n'th element in a vector (an array) compared to that of comparing a natural number with a list of natural number of size n? I suppose they are both O(n) but with significantly different coefficients.
No; array lookup is constant-time.
The reason for this is that computer memory is constructed so as to allow for constant-time access to any element as long as you have the address of it. An array is a contiguous sequence of elements, and therefore, you can compute the address of the desired element from the start address, the index, and the element size. (All elements must be of the same size; this might appear not to be the case in languages that allow you to put different kinds of elements into the same array, but in that situation, the elements of the array are actually references (memory addresses, in practice) to the objects.)

Why is accessing any single element in an array done in constant time ( O(1) )?

According to Wikipedia, accessing any single element in an array takes constant time as only one operation has to be performed to locate it.
To me, what happens behind the scenes probably looks something like this:
a) The search is done linearly (e.g. I want to access element 5. I begin the search at index 0, if it's not equal to 5, I go to index 1 etc.)
This is O(n) -- where n is the length of the array
b) If the array is stored as a B-tree, this would give O(log n)
I see no other approach.
Can someone please explain why and how this is done in O(1)?
An array starts at a specific memory address start. Each element occupies the same amount of bytes element_size. The array elements are located one after another in the memory from the start address on. So you can calculate the memory address of the element i with start + i * element_size. This computation is independent of the array size and is therefor O(1).
In theory elements of an array are of the same known size and they are located in a continuous part of memory so if beginning of the array is located at A memory address if you want to access any element you have to compute its address like this:
A + item_size*index so this is a constant time operation.
Accessing a single element is NOT finding an element whose value is x.
Accessing an element i means getting the element at the i'th position of the array.
This is done in O(1) because it is pretty simple (constant number of math calculations) where the element is located given the index, the beginning of the array and the size of each element.
RAM memory offers a constant time (or to be more exact, a bounded time) to access each address in the RAM, and since finding the address is O(1), and retrieving the element in it is also O(1), it gives you total of O(1).
Finding if an element whose value is x is actually Omega(n) problem, unless there is some more information on the array (sorted, for example).
Usually an array is organized as a continuous block of memory where each position can be accessed by means of an index calculation. This index calculation cannot be done in constant time for arrays of arbitrary size, but for reasons of addressable space, the numbers involved are bounded by machine word size, so an assumption of constant time is justified.
If you have array of Int's. Each int is 32 bit's in java . If you have for example 10 integers in java it means you allocate memory of 320 bits. Then computer know
0 - index is at memory for example - 39200
last index is at memory 39200 + total memory of your array = 39200+320= 39520
So then if you want to access index 3. Then it is 39200 + 32*3 = 39296.
It all depends how much memory your object takes which you store in array. Just remember arrays take whole block of memory.

why does accessing an element in an array take constant time?

Lets say I have an array as:
int a[]={4,5,7,10,2,3,6}
when I access an element, such as a[3], what does actually happen behind the scenes?
Why do many algorithm books (such as the Cormen book...) say that it takes a constant time?
(I'm just a noob in low-level programming so I would like to learn more from you guys)
The array, effectively, is known by a memory location (a pointer). Accessing a[3] can be found in constant time, since it's just location_of_a+3*sizeof(int).
In C, you can see this directly. Remember, a[3] is the same as *(a+3) - which is a bit more clear in terms of what it's doing (dereferencing the pointer "3 items" over).
an array of 10 integer variables, with indices 0 through 9, may be stored as 10 words at memory addresses 2000, 2004, 2008, … 2036, so that the element with index i has the address 2000 + 4 × i.
this process take one multiplication and one addition .since these two operation take constant time.so we can say the access can be perform in constant time
Just to be complete, "what structure is accessed in linear time?" A Linked List structure is accessed in linear time. To get the n element you have to travel through n-1 previous elements. You know, like a tape recorder or a VHS cassette, where to go to the end of the tape/VHS you had to wait a long time :-)
An array is more similar to an hard disk: every point is accessible in "constant" time :-)
This is the reason the RAM of a computer is called RAM: Random Access Memory. You can go to any location if you know its address without traversing all the memory before that location.
Some persons told me that HD access isn't really in constant time (where by access I mean "time to position the head and read one sector of the HD"). I have to say that I'm not sure of it. I have googled around and I haven't found anyone speaking of it. I DO know that the time isn't linear, because it is still accessed randomly. In the end, if you think that HD access isn't constant enough for you (but then, what is constant? the access of the RAM? considering Cache, Prefetching, Data Locality and Compiler optimizations?), feel free to consider the sentence as An array is more similar to an USB disk stick: every point is accessible in "constant" time :-)
Because arrays are stored in memory sequentially. So actually, when you access array[3] you are telling the computer, "Get the memory address of the beginning of array, then add 3 to it, then access that spot." Since adding takes constant time, so does array access!
"constant time" really means "time that doesn't depend on the 'problem size'". For the 'problem' "get something out of a container", the 'problem size' is the size of the container.
Accessing an array element takes basically the same amount of time (this is a simplification) regardless of the container size, because a fixed set of steps is used to retrieve the element: its location in memory (this is also a simplification) is calculated, and then the value at that location in memory is retrieved.
A linked list, for example, can't do this, because each link indicates the location of the next one. To find an element you have to work through all the previous ones; on average, you'll work through half the container, so the size of the container obviously matters.
Array is collection of similar types of data. So all the elements will take same amount of memory.Therefore if you know the base address of array and type of data it holds you can easily get element Array[i] in constant time using formula stated below:
int takes 4 bytes in a 32 bit system.
int array[10];
base address=4000;
location of 7th element:4000+7*4.
array[7]=array[4000+7*4];
Hence, its clearly visible you can get ith element in constant time if you know the base address and type of data it holds.
Please visit this link to know more about array data structure.
An array is sequential, meaning that, the next element's address in the array is next to the present one's. So if you want to get 5th element of an array, you calculate the address of 5th element by summing up the base address of the array with 5. This direct address is now directly used to get the element at that address.
You may now further ask the same question here- "How does the computer knows/accesses the calculated address directly?" This is the nature and the principle of computer memory (RAM). If you are further interested in how RAM accesses any address in constant time, you can find it in any computer organization text or you can just google it.
If we know memory location that need to be accessed then this access is in constant time. In case of array the memory location is calculated by using base pointer, index of element and size of element. This involves multiplication and addition operation which takes constant time to execute. Hence element access inside array takes constant time.

Resources