Chapter 4: Complexity, Memory and Performance Analysis
4.10Beginner5 topics14 min2 interactive animations

Complexity comparison

Five comparisons that decide real design choices: arrays versus linked lists, hashing's expected versus worst case, balanced trees, the comparison-sorting lower bound, and adjacency lists versus matrices for graphs.

Learning goals

  • Compare structures operation by operation
  • Explain the n log n sorting lower bound
  • Choose a graph representation from density

Prerequisites

Common growth functionsComplexity scenarios
4.10.1

Arrays vs linked lists

Arrays win on indexed access and traversal because their elements are contiguous: O(1) reads and few cache misses. Linked lists win only on insertion or removal at a position you already hold, where an array must shift elements. In practice, even such workloads often favour arrays until n is very large.

Count the memory reads for reaching element k in the animation.

OperationArray / ArrayListLinked list
Access by indexO(1)O(n)
Search by valueO(n)O(n)
Insert at endamortised O(1)O(1) with a tail pointer
Insert at frontO(n)O(1)
Insert at known nodeO(n)O(1)
Memory per element4-8 bytesabout 24-32 bytes

Reading element k: array vs linked list

Interactive · edit the input

Your input

Try

array memory (value, address)

12@1000
7@1004
31@1008
4@1012
19@1016
8@1020
25@1024
Setup

The 7 values sit in consecutive memory cells, 4 bytes apart, starting at address 1000.

Step 1 / 3
Java
1static int getFromArray(int[] arr, int k) {
2 return arr[k]; // address = base + k * 4: one memory read
3}
4
5static int getFromList(Node head, int k) {
6 Node cur = head;
7 for (int i = 0; i < k; i++) {
8 cur = cur.next; // pointer chase: one read per hop
9 }
10 return cur.value;
11}

Live state

0 memory reads

k

5

base

1000

No condition evaluated on this step
Execution trace (dry run table)Show 3 steps
StepLineStateWhat happens
1L1k=5 base=1000The 7 values sit in consecutive memory cells, 4 bytes apart, starting at address 1000.
2L2k=5 address=1020Address = 1000 + 5 × 4 = 1020. One multiplication and one addition give the location, no matter how large k is.
3L2return=8return 8 with a single memory read: O(1) random access.
4.10.2

Hashing expected/worst-case

A hash table gives expected O(1) get, put and remove when the hash function spreads keys evenly and the load factor is bounded. In the worst case all keys land in one bucket: O(n) for a list-based bucket, O(log n) for Java 8+ HashMap, which converts long buckets to balanced trees. Resizing costs O(n) occasionally but is amortised O(1).

Adversarial or poorly distributed keys are the practical risk; mutable keys and missing hashCode implementations are the common bugs.

OperationExpectedWorst case (Java 8+)
get / containsO(1)O(log n)
putO(1) amortisedO(log n)
removeO(1)O(log n)
iterate allO(n + capacity)same
4.10.3

Balanced trees

A balanced binary search tree keeps its height O(log n) with rotations, so search, insert and delete are O(log n) in the worst case, and keys stay in sorted order for range and nearest-key queries. AVL trees have height at most about 1.44 log₂ n and red-black trees at most 2 log₂(n + 1); Java's TreeMap is a red-black tree.

An unbalanced tree degrades to a chain of height n on sorted input.

StructureSearchSorted orderRange query
Hash tableO(1) expectednono
Sorted arrayO(log n)yesyes (insert O(n))
Balanced BSTO(log n) worstyesyes
Plain BSTO(n) worstyesyes
4.10.4

Sorting lower bound

Any algorithm that sorts only by comparing elements needs Ω(n log n) comparisons in the worst case. A sorting algorithm is a binary decision tree whose leaves are the possible orderings; there are n! of them, and a binary tree with n! leaves has height at least log₂(n!) = Θ(n log n). So merge sort and heap sort are asymptotically optimal among comparison sorts.

Non-comparison sorts (counting, radix, bucket) escape the bound by using the structure of the keys. The chart compares measured growth of the quadratic and n log n sorts.

nlog₂(n!) (minimum comparisons)
4about 4.6, so at least 5
10about 21.8, so at least 22
100about 525
1,000about 8,530

Comparisons as the input grows

Measured by running each trace
Input order
069138207276n=4n=8n=12n=16n=20n=24
  • Bubble275
  • Selection276
  • Insertion162
  • Quick (last pivot)104
  • Heap147
  • Merge80
  • Lower bound ⌈log₂ n!⌉80

Numbers at the right are comparisons for n = 24. The dashed line is the fewest comparisons any comparison sort can use in the worst case. Switch to “sorted” and “reverse” to see which algorithms notice the order.

4.10.5

Graph adjacency list vs matrix

An adjacency matrix is a V × V array: O(V²) memory, O(1) test for an edge, O(V) to list the neighbours of a vertex. An adjacency list stores each vertex's neighbours: O(V + E) memory, O(degree) edge test and O(degree) neighbour listing. Use the matrix for dense graphs (E close to V²) or when constant-time edge checks matter; use lists for sparse graphs, which are the majority.

A road network with 10⁶ intersections and 3 × 10⁶ roads fits as a list but would need 10¹² cells as a matrix.

OperationAdjacency listAdjacency matrix
MemoryO(V + E)O(V²)
Is there an edge (u, v)?O(deg u)O(1)
Visit neighbours of uO(deg u)O(V)
Traverse whole graph (BFS/DFS)O(V + E)O(V²)
Add an edgeO(1)O(1)
Java
1int V = 4;
2boolean[][] matrix = new boolean[V][V];
3List<List<Integer>> list = new ArrayList<>();
4for (int i = 0; i < V; i++) list.add(new ArrayList<>());
5int[][] edges = {{0, 1}, {1, 2}, {2, 3}};
6for (int[] e : edges) { matrix[e[0]][e[1]] = matrix[e[1]][e[0]] = true; list.get(e[0]).add(e[1]); list.get(e[1]).add(e[0]); }

Practice ladder

Now try it yourself

Easy

  • When is a linked list better than an ArrayList?
  • Which graph representation suits 10⁶ vertices and 3 × 10⁶ edges?

Medium

  • Explain why a hash table has an O(log n) worst case in Java 8+
  • Compute the minimum number of comparisons needed to sort 5 items

Advanced

  • Prove that log₂(n!) is Ω(n log n) using the n/2 largest factors

Key takeaways

  • Arrays beat linked lists for almost everything except holding a node and editing around it.
  • Hashing is expected O(1); balanced trees give O(log n) with order.
  • Comparison sorting needs Ω(n log n); graph density picks list or matrix.