Foundations
Arrays as a Data Structure
Arrays from the data-structure point of view: O(1) access, the cost of insertion and deletion by shifting, and when an array is the right choice.
You already know how to use arrays from the C course. Here we look at them as a data structure: what each operation costs.
An array stores elements in contiguous memory. Because every element has the same size, the address of a[i] is simply base + i × size. That makes access O(1) — the computer jumps straight there.
a[3] is at base + 3 × 4 bytes. No searching needed, so indexing is O(1). The _ cells are spare capacity.Insertion at a position
To insert at index pos, every element from pos onwards must shift one place right to make room. Inserting at the front of n elements moves all n: O(n).
#include <stdio.h>
int insertAt(int a[], int n, int cap, int pos, int value) {
if (n == cap || pos < 0 || pos > n) return n; // full or invalid position
for (int i = n; i > pos; i--) // shift right, starting from the end
a[i] = a[i - 1];
a[pos] = value;
return n + 1; // new size
}
void print(const int a[], int n) {
for (int i = 0; i < n; i++) printf("%d ", a[i]);
printf("\n");
}
int main(void) {
int a[10] = {12, 25, 31, 47, 58};
int n = 5;
n = insertAt(a, n, 10, 2, 99);
print(a, n);
n = insertAt(a, n, 10, 0, 7);
print(a, n);
n = insertAt(a, n, 10, n, 100); // at the end: no shifting, O(1)
print(a, n);
return 0;
}12 25 99 31 47 58 7 12 25 99 31 47 58 7 12 25 99 31 47 58 100
Deletion at a position
Deleting shifts the later elements left to close the gap: also O(n) in the worst case.
#include <stdio.h>
int deleteAt(int a[], int n, int pos) {
if (pos < 0 || pos >= n) return n;
for (int i = pos; i < n - 1; i++)
a[i] = a[i + 1];
return n - 1;
}
int main(void) {
int a[] = {12, 25, 31, 47, 58};
int n = 5;
n = deleteAt(a, n, 1);
for (int i = 0; i < n; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}12 31 47 58
Array operation costs
| Operation | Cost | Why |
|---|---|---|
Access a[i] |
O(1) | address arithmetic |
Update a[i] = x |
O(1) | address arithmetic |
| Search (unsorted) | O(n) | may check every element |
| Search (sorted) | O(log n) | binary search |
| Insert / delete at end | O(1) | nothing to shift |
| Insert / delete at front or middle | O(n) | shifting |
Strengths and weaknesses
Use an array when you need fast random access by index, the size is known or changes rarely, and you mostly add or remove at the end.
Avoid an array when you insert and delete in the middle a lot, or the size is completely unpredictable — that is where linked lists shine.
Merging two sorted arrays
A pattern you will reuse in merge sort: walk both arrays with two indexes, always taking the smaller front element. It runs in O(n + m).
#include <stdio.h>
int main(void) {
int a[] = {3, 8, 15, 21}, b[] = {1, 9, 10, 22, 30};
int n = 4, m = 5, c[9], i = 0, j = 0, k = 0;
while (i < n && j < m) c[k++] = (a[i] <= b[j]) ? a[i++] : b[j++];
while (i < n) c[k++] = a[i++];
while (j < m) c[k++] = b[j++];
for (int t = 0; t < k; t++) printf("%d ", c[t]);
printf("\n");
return 0;
}1 3 8 9 10 15 21 22 30
Test yourself
4 questions · pick an answer to check it instantly
- 1
Why is accessing
a[i]O(1)?No traversal is needed; the address is arithmetic. - 2
What is the worst-case cost of inserting at the front of an array holding
nelements?Every existing element must shift one position right. - 3
Merging two sorted arrays of sizes
nandmtakes...Each step copies one element, and there are n + m elements in total. - 4
Which situation suits an array least?
Middle insertions require O(n) shifting each time.