Chapter 1: Introduction to Data Structures and Algorithms
1.04Beginner7 topics14 min1 interactive animation

Classifying data structures

Data structures can be grouped by how they store values: primitive or composite, linear or hierarchical, fixed or growing, contiguous or linked, uniform or mixed, destructive or persistent. These labels predict performance before you read any code.

Learning goals

  • Place a structure on each classification axis
  • Explain what contiguous storage gains and costs compared with linked storage
  • Describe persistent (immutable, shareable) structures

Prerequisites

Core vocabulary
1.04.1

Primitive vs non-primitive

Primitive types (int, long, double, char, boolean, …) hold a single value directly. Non-primitive (reference) types such as arrays, String and collections are objects that hold references and have methods.

Collections cannot store primitives, only their wrappers (Integer, Long), so List<int> does not compile and List<Integer> boxes every value. That boxing has a real memory and time cost, covered in Chapter 4.

PrimitiveNon-primitive
int, long, double, char, booleanint[], String, ArrayList, user classes
Value stored in placeReference to an object on the heap
No null, no methodsMay be null, has methods
1.04.2

Linear vs non-linear

In a linear structure each element has at most one predecessor and one successor: arrays, linked lists, stacks and queues. In a non-linear structure an element can connect to several others: trees and graphs.

Linear structures are traversed from one end. Non-linear ones need a traversal strategy (depth-first or breadth-first).

LinearNon-linear
Array, list, stack, queue, dequeTree, heap, trie, graph
One path through the dataBranching paths
Traverse with a loopTraverse with recursion or a queue/stack
1.04.3

Static vs dynamic

A static structure has a fixed size chosen at creation: a Java array. A dynamic structure can grow and shrink: ArrayList, LinkedList, HashMap.

Dynamic does not mean free. An ArrayList is built on an array that it replaces with a bigger one when full; Chapter 4 shows why that still costs O(1) per append on average.

Java
1int[] fixed = new int[5]; // length is 5 forever
2List<Integer> grows = new ArrayList<>();
3for (int i = 0; i < 1000; i++) grows.add(i); // size changes as needed
1.04.4

Contiguous vs linked

Contiguous structures (arrays) keep elements next to each other in memory, so element k is at base + k × size: one calculation, one read, and CPU caches love it. Linked structures keep elements in separate objects joined by references, so reaching element k means following k links.

In exchange, a linked list can insert or remove at a known node in O(1) without shifting anything. Run the animation in both modes to count memory reads.

OperationArrayLinked list
Read element kO(1)O(k)
Insert at frontO(n) shiftO(1)
Insert after a known nodeO(n) shiftO(1)
Memory per elementjust the valuevalue + reference + object header
Cache behaviourexcellentpoor

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.
1.04.5

Homogeneous vs heterogeneous

A homogeneous structure holds one element type (int[], List<String>). A heterogeneous one mixes types: a record or class with different fields, or List<Object>.

Prefer homogeneous collections of a well-chosen element type, and put mixed data into a class or record so the compiler can check it.

Java
1int[] scores = {90, 85, 77}; // homogeneous
2record Student(String name, int grade) {} // heterogeneous fields in one type
3List<Student> roster = List.of(new Student("Ana", 9));
1.04.6

Persistent vs ephemeral

An ephemeral structure is changed in place; the old version is gone. A persistent structure keeps every earlier version available, usually by sharing unchanged parts between versions instead of copying them.

A persistent linked list shows the idea: adding at the front creates one new node whose next points at the old list, so both versions coexist.

Java
1record Cons(int head, Cons tail) {}
2Cons a = new Cons(3, new Cons(2, null)); // [3, 2]
3Cons b = new Cons(9, a); // [9, 3, 2]: shares all of a
4// a is unchanged and still [3, 2]; b adds one node
1.04.7

Mutable vs immutable

A mutable structure can be modified after construction; an immutable one cannot, so it is safe to share across threads and to use as a key. List.of, Set.of and Map.of create immutable collections that throw UnsupportedOperationException on modification.

Immutability costs copying when you want a changed version, which is why persistent structures share parts.

Java
1List<Integer> fixed = List.of(1, 2, 3);
2// fixed.add(4); // throws UnsupportedOperationException
3List<Integer> editable = new ArrayList<>(fixed);
4editable.add(4); // fine: a mutable copy

Practice ladder

Now try it yourself

Easy

  • Classify array, linked list, stack, tree and hash map as linear or non-linear
  • Why can List<int> not be written in Java?

Medium

  • List two operations where an array beats a linked list and two where it loses
  • Create an immutable list of 5 values in Java and show what happens when you modify it

Advanced

  • Implement a persistent stack with push and pop where old versions stay valid

Key takeaways

  • Contiguous storage gives O(1) indexing and great cache use; linked storage gives cheap local inserts.
  • Collections hold references, so primitives are boxed.
  • Persistent structures share unchanged parts so every version stays usable.