# Introduction To Array Data Structure

This article is an introductory lesson on array ds with sketches, memory diagrams, strengths and weaknesses with examples.

## Table of Contents

## Introduction

Arrays are built in most programming languages. They are the most fundamental data structures of all in computer science. Arrays are the building blocks for many other, more complex data structures.

`Why do we need an array to store elements? Why can't we make use of ``int`

primitive type?

## Why not make use of primitives?

In Java `int`

takes `4`

bytes. So the declaration below occupies `4`

bytes of memory.

`int a = 100;`

What if we want to store six `int`

values (or `24`

bytes)? We need to use six different variables individually, each occupying `4`

bytes so that the total will be `6 * 4 = 24`

bytes.

```
// each of the following occupies 4 bytes, which is 6 * 4 bytes
int a1 = 100;
int a2 = 200;
int a3 = 300;
int a4 = 400;
int a5 = 500;
int a6 = 600;
```

Creating six different variables is a bit dirty and not a good idea. What if we wanted to store a million entries, are we supposed to create a million different variables? 😢 Isn't this bad coding?

Instead, we store the million items in an array sequentially in an `int[] array`

. This can be achieved easily by following the declaration and initialization with values.

`int[] array = {100, 200, 300, 400, 500, 600};`

Isn't the array beautiful? 🤩

## What is an array?

In Java and many other languages, arrays are static(fixed size). Array organizes items sequentially, one after another, in memory.

The items could be `Integer`

, `String`

, `Object`

, – anything. The items are stored in contiguous (adjacent to each other) memory locations.

Each position in the array has an index, starting at the `0`

^{th} index. In Java, integers take `4`

bytes, so the memory addresses of each adjacent element are added by `4`

bytes.

## Sketch

A simple sketch of this is as follows.

If we say our array memory, location/address starts from `100`

, then the following integer address will start from `104(100+4)`

bytes, and so on.

In the above illustration/figure, we have an array with `6`

elements in it, with a memory address pointed from `100`

to `120`

. So theoretically, anything that we store after this array takes the address from `124`

.

Note:In Java, we have to specify the size of the array ahead of time before initializing the array.

We knew everything on the computer is stored in bits `0`

or `1`

. Let us see how these array numbers from the above sketch are stored in memory and addressed in binary.

## Declaration and initialization

Consider an array `A[]`

that has `5`

elements. To access the last element of the array, we use `A[4]`

.

With this knowledge, if `N`

is the array length, then `(N-1)`

is how we access the last element. There are two ways we can declare and initialize the array in Java.

```
// approach 1
int[] A = new int[5];
A[0] = 1;
A[1] = 2;
A[2] = 3;
A[3] = 4;
A[4] = 5;
// approach 2
int[] A = {1, 2, 3, 4, 5};
```

This small illustration helps you understand how we access array elements using their indexes.

## Size vs capacity

The starting size of an array depends on the array declaration.

`int[] A = new int[10];`

You inserted numbers `1`

, `2`

, `3`

, and `4`

into the above array.

```
A[0] = 1;
A[1] = 2;
A[2] = 3;
A[3] = 4;
```

At this point, the length/size of the array is `4`

and the capacity of the array that has room to store elements is `10`

.

## How to access elements?

Following is a simple sketch of an array `A`

with a capacity `N`

.

`int[] A;`

Since arrays in Java starts from `0`

^{th} index. If you want to access the first element, you need to give `A[0]`

, and `A[1]`

for accessing the second element, and so on `A[N-1]`

to access the last element.

What happens if we do `A[-100]`

, `A[N]`

, and `A[N+1]`

? 🤔

You guessed it. We run into `ArrayIndexOutOfBoundsException`

.

```
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 5
at array.ArrayIntroduction.main(ArrayIntroduction.java:20)
```

At most, we can access the last element of the array using `A[N-1]`

.

## How to print array elements

A simple snippet to print the array elements from `0`

to `(N-1)`

index.

```
public class PrintElements {
public static void main(String[] args) {
int[] A = {1, 2, 3, 4, 5};
int N = A.length;
for (int i = 0; i < N; i++) {
System.out.println(A[i]);
}
}
}
```

The time and space complexity to print these array elements are:

**Time complexity** - `O(N)`

- We iterated over all the array elements of size `N`

, so the time complexity is linear.

**Space complexity **- `O(1)`

- No algorithmic memory is used here. We just used the input `A[]`

memory, hence Constant time.

## Strengths

** Fast lookups**: Retrieving the element at a given index takes

`O(1)`

time, regardless of the array's length.** Fast appends**: Adding a new element at the end of the array takes

`O(1)`

time if the array has space.## Weaknesses

** Fixed-size**: You need to specify how many elements you will store in your array ahead of time. (Unless you're using a fancy dynamic array).

** Memory unused or wasted**: Imagine an array with a capacity of

`5`

. We have two elements to store in this array, and then we are wasting three unfilled cells and a waste of memory, which means `3*(4 bytes) = 12 bytes`

of memory is wasted (integer takes `4`

bytes).** Size doubling**: Let us consider an array with a capacity of

`5`

elements. But the elements we want to store in this array are more, which means we have to double the size, create a new array, copy the old array elements and add new elements. The time complexity is `O(n)`

.__ Costly inserts__: Inserting an element at the end of the array takes

`O(1)`

time. But, inserting an element at the start/middle of the array takes `O(n)`

time. Why?If we want to insert something into an array, first, we have to make space by "*scooting over*" everything starting at the index we're inserting into, as shown in the image. In the worst case, we're inserting into the 0^{th} index in the array (prepending), so we have to "*scoot over*" everything in the array.

That's `O(n)`

time.

Inserting an element at the `2`

^{nd} `index`

and moving the rest of the element right shift each once. The resultant array becomes – `{ A, B, C, D, E }`

.

I recommend you read Array insertions and shifting algorithms(link below) with a clear explanation with code snippets and sketches to understand why these inserts are expensive at the start and middle.

** Costly deletes**: Deleting an element at the end of the array takes

`O(1)`

time, which is the best case. In computer science, we only care about the worse case scenarios when working on algorithms. But, when we remove an element from the middle or start of the array, we have to fill the gap by scooting over all the elements after it. This will be `O(n)`

if we consider a case of deleting an element from the 0theindex.Deleting an element at the `3`

^{rd}`index`

and filling the gap by left-shifting the rest of the elements; the resultant array becomes – `{ A, B, C, D, E }`

.

## Big-O worst-case time complexities

Operation | Worst-Case Time Complexity |
---|---|

Lookup/access a value at a given index | O(1) |

Update a value at a given index | O(1) |

Insert at the beginning/middle | O(N) |

Insert at the end | O(N) |

Append at the end | O(1) |

Delete at the beginning/middle | O(N) |

Delete at the end | O(1) |

So far, we covered the basics of array data structure. In computer science, arrays are the building blocks for many other, more complex data structures.

In the next lesson, you will learn about the insertion and deletion algorithms on arrays. They are the simplest yet most powerful and helps you when working on array problems.

## 👨🏻💻 Gopi Gorantala Newsletter

Join the newsletter to receive the latest updates in your inbox.