This page has been replaced by the new Data Structures sub-page structure. Content is preserved here for reference while sub-pages are built out.
Data Structures
IB Syllabus: B2.2 — Data structures
Table of Contents
- Static vs Dynamic Structures
- 1D Arrays
- Common Array Operations
- Copying Arrays
- 2D Arrays
- ArrayList
- Stacks
- Queues
- Choosing the Right Structure
- Quick Check
- Trace Exercise
- Practice Exercises
Static vs Dynamic Structures
Every program needs to store collections of data. The question is how much flexibility you need.
| Feature | Static (Array) | Dynamic (ArrayList, Stack, Queue) |
|---|---|---|
| Size | Fixed at creation | Grows or shrinks at runtime |
| Memory | Allocated once | Allocated as needed |
| Access | Direct by index | Depends on type |
| Speed | Very fast | Slight overhead |
The key insight: static structures are simpler and faster when you know the size in advance. Dynamic structures are necessary when size changes at runtime — for example, adding items to a shopping cart or managing a print queue.
Picture it: Imagine a row of numbered mailboxes starting at 0. Each box holds exactly one item. The index is its position from the start — so box 0 is at the very beginning. How many boxes would you have if the last index is 4?
1D Arrays
An array stores a fixed number of values of the same type in contiguous memory. Each element is accessed by its index, starting at 0.
Declaring and Initialising
// Declare with a fixed size — all elements default to 0
int[] scores = new int[5];
// Declare and initialise with known values
int[] scores = {85, 72, 91, 60, 78};
// Access by index
System.out.println(scores[0]); // 85
System.out.println(scores[4]); // 78
scores[2] = 95; // modify an element
Array Length
System.out.println(scores.length); // 5 — note: no parentheses, it's a property
Traversal
The standard pattern to visit every element:
for (int i = 0; i < scores.length; i++) {
System.out.println("scores[" + i + "] = " + scores[i]);
}
Index
iruns from0toscores.length - 1. Accessingscores[scores.length]causes anArrayIndexOutOfBoundsException.
Common Array Operations
These operations appear frequently in exam questions and real programs. Each one is a fundamental algorithm — understanding the logic matters more than memorising the code.
Find Maximum and Minimum
int[] numbers = {34, 67, 12, 89, 45};
int max = numbers[0]; // assume first element is the largest
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
}
System.out.println("Maximum: " + max); // 89
The same pattern applies for minimum — just flip > to <.
Sum and Average
int sum = 0;
for (int i = 0; i < numbers.length; i++) {
sum = sum + numbers[i];
}
double average = (double) sum / numbers.length;
System.out.println("Sum: " + sum + ", Average: " + average);
Count Occurrences
int target = 45;
int count = 0;
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == target) {
count++;
}
}
System.out.println(target + " appears " + count + " time(s).");
Duplicate Detection
Two common approaches, each answering a different question:
int[] numbers = new int[5];
// ... filled with values ...
// -------------------------------------------------------
// METHOD 1: Are ANY two elements the same?
// Compare every pair using nested loops
// -------------------------------------------------------
boolean duplicateFound = false;
for (int i = 0; i < numbers.length - 1 && !duplicateFound; i++) {
for (int j = i + 1; j < numbers.length && !duplicateFound; j++) {
if (numbers[i] == numbers[j]) {
duplicateFound = true;
System.out.println("Duplicate found: " + numbers[i]
+ " at index " + i + " and index " + j);
}
}
}
// -------------------------------------------------------
// METHOD 2: Are ALL elements the same value?
// Compare every element against the first
// -------------------------------------------------------
boolean allSame = true;
int first = numbers[0];
for (int i = 1; i < numbers.length && allSame; i++) {
if (numbers[i] != first) {
allSame = false;
}
}
System.out.println("All same: " + allSame);
Notice the
&& !duplicateFoundcondition in Method 1. This stops the inner loop as soon as a match is found — there is no point continuing. This is called an early exit and it is more efficient than always running to the end.
Try it first: Before reading this section, write
int[] b = a;, then changeb[0] = 99and printa[0]. Does the result surprise you?
Copying Arrays
The Reference Trap
Arrays in Java are objects. When you assign one array variable to another, you are copying the reference (the address in memory), not the data.
int[] original = {1, 2, 3, 4, 5};
int[] copy = original; // WRONG: both variables point to the same array
copy[0] = 99;
System.out.println(original[0]); // 99 — original changed too!
In memory, both original and copy point to the same block of data. Modifying one modifies both.
The Correct Way: Element-by-Element Copy
int[] original = {1, 2, 3, 4, 5};
int[] copy = new int[original.length]; // allocate a new, separate array
for (int i = 0; i < original.length; i++) {
copy[i] = original[i]; // copy each value individually
}
copy[0] = 99;
System.out.println(original[0]); // 1 — original is untouched
Resizing an Array
Arrays have a fixed size. To “grow” an array, you must create a larger one and copy the data across:
int[] data = {10, 20, 30}; // original array, size 3
// Step 1: Create a larger temporary array
int[] temp = new int[data.length + 2];
// Step 2: Copy original elements into temp
for (int i = 0; i < data.length; i++) {
temp[i] = data[i];
}
// Step 3: Reassign the reference
data = temp;
// Step 4: Null the temp variable (clean up the old reference)
temp = null;
System.out.println(data.length); // 5
This four-step resize pattern is exactly how dynamic data structures (like ArrayList) work internally — they just do it automatically behind the scenes. Understanding it manually is the point.
2D Arrays
A 2D array is an array of arrays — a table with rows and columns.
// 3 rows, 4 columns — like a grid
int[][] grid = new int[3][4];
// Or initialise with values
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Access: matrix[row][column]
System.out.println(matrix[1][2]); // 6 (row 1, column 2)
Traversing a 2D Array
// Print the entire matrix
for (int row = 0; row < matrix.length; row++) {
for (int col = 0; col < matrix[row].length; col++) {
System.out.print(matrix[row][col] + "\t");
}
System.out.println();
}
A 2D array is useful for: grade books (students × assignments), game boards (rows × columns), spreadsheet data.
ArrayList
An ArrayList is like an array that can grow and shrink. It stores objects (not primitives), and it handles resizing automatically.
import java.util.ArrayList;
ArrayList<String> names = new ArrayList<>();
// Add elements
names.add("Alice");
names.add("Bob");
names.add("Charlie");
// Access by index
System.out.println(names.get(0)); // Alice
// Size
System.out.println(names.size()); // 3 — note: .size(), not .length
// Remove by index
names.remove(1); // removes "Bob"
System.out.println(names); // [Alice, Charlie]
// Check if contains
System.out.println(names.contains("Alice")); // true
// Traverse
for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i));
}
| Operation | Array | ArrayList |
|---|---|---|
| Access | arr[i] | list.get(i) |
| Length/Size | arr.length | list.size() |
| Add | Not possible | list.add(value) |
| Remove | Not possible | list.remove(index) |
| Fixed size? | Yes | No |
ArrayListstores objects only. For primitive types, Java uses wrapper classes:Integerforint,Doublefordouble,Booleanforboolean. Java automatically converts between them (autoboxing).
Think about it: What does Ctrl+Z do? If you press it three times, what gets undone first — the first action or the most recent? What does that tell you about how the undo history must be stored?
Stacks
A stack is an abstract data structure that enforces a specific access rule: Last In, First Out (LIFO). Only the top element is accessible.
Think of a stack of plates — you add to the top and remove from the top.
| Operation | Meaning |
|---|---|
push(value) | Add an item to the top |
pop() | Remove and return the top item |
peek() | Look at the top item without removing it |
isEmpty() | Check if the stack is empty |
import java.util.Stack;
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
System.out.println(stack.peek()); // 30 — look at top
System.out.println(stack.pop()); // 30 — remove top
System.out.println(stack.pop()); // 20
System.out.println(stack.isEmpty()); // false — 10 still there
Why stacks matter: the call stack in your program is literally a stack — every time a method is called, a frame is pushed; when it returns, it is popped. Undo/redo in editors, browser back buttons, and expression evaluation all use stacks.
On IB exams, you may be asked to trace push/pop operations on a stack. Always keep track of the top pointer and draw the stack contents after each operation.
Think about it: When you send three documents to the printer, which one prints first? What would happen if the printer used a stack instead of a queue?
Queues
A queue enforces First In, First Out (FIFO) — the first item added is the first item removed. Think of a queue at a ticket counter.
| Operation | Meaning |
|---|---|
enqueue(value) | Add an item to the back |
dequeue() | Remove and return the front item |
front() / peek() | Look at the front item |
isEmpty() | Check if the queue is empty |
import java.util.LinkedList;
import java.util.Queue;
Queue<String> queue = new LinkedList<>();
queue.add("Alice"); // enqueue
queue.add("Bob");
queue.add("Charlie");
System.out.println(queue.peek()); // Alice — look at front
System.out.println(queue.poll()); // Alice — remove front
System.out.println(queue.poll()); // Bob
System.out.println(queue.isEmpty()); // false — Charlie still waiting
Why queues matter: print queues, task schedulers, network packet buffers, and any system where order of arrival must be respected all use queues. The OS process scheduler you studied in the operating systems layer uses a queue.
LinkedListis one common Java implementation of a Queue. In IB exams, questions about queues are usually abstract (trace enqueue/dequeue operations) rather than code-specific.
Choosing the Right Structure
| Situation | Best choice |
|---|---|
| Fixed number of items, fast index access | Array |
| Number of items changes at runtime | ArrayList |
| Need LIFO (undo, backtracking) | Stack |
| Need FIFO (order matters, job queue) | Queue |
| Tabular data (grid, board, matrix) | 2D Array |
Quick Check
Q1. Given int[] arr = new int[6], what is the last valid index?
Q2. int[] b = a; b[0] = 99; — what is a[0]?
Q3. After push(10), push(20), push(30), pop() — what does peek() return?
Q4. Which data structure enforces FIFO (First In, First Out)?
Q5. Which declaration is valid for an ArrayList of integers?
Trace Exercise
Stack operations — fill in the top element and size after each operation.
Stack<Integer> s = new Stack<>();
s.push(5);
s.push(3);
s.push(8);
s.pop();
s.push(1);
s.pop();
| Operation | Top element | Size |
|---|---|---|
push(5) | ||
push(3) | ||
push(8) | ||
pop() | ||
push(1) | ||
pop() |
What does s.peek() return after all operations?
What are the remaining stack contents, bottom to top?
Practice Exercises
- Write a program that fills an array of 10 integers with values entered by the user, then prints the minimum, maximum, and average.
- Write code in
mainthat creates a reversed copy of{1, 2, 3, 4, 5}. Store the reversed elements in a new array without modifying the original, then print both arrays. - Write code in
mainthat counts how many elements in{34, 67, 12, 89, 45}are greater than 50. Print the result. - Create a 3×3 array representing a tic-tac-toe board (using
char). Write a loop to print it as a grid. - Trace exercise — draw the contents of this stack after each line:
Stack<Integer> s = new Stack<>(); s.push(5); s.push(3); s.push(8); s.pop(); s.push(1); s.pop(); - Challenge: Write a program that reads lines from the user until they enter “quit”. Store all lines in an
ArrayList, then print them in reverse order.