2.1 - Elements of computational thinking
2.1.1–2.1.5 The five aspects of computational thinking
Why needed: complex real-world problems are too detailed to solve directly, so abstraction makes them manageable.
Examples: a map is an abstraction of the real world; a class is an abstraction of a real-world object.
Caching: storing results of expensive operations for reuse. Benefit: faster. Drawback: uses memory, stale data.
Reusable components: write code once, use many times. Reduces duplication, easier to maintain.
Closely related to decomposition: identifying which components are needed and in what order.
Examples: if/else conditions, loops with conditions, case statements.
Benefits: faster execution for tasks that can be parallelised.
Trade-offs: not all problems can be parallelised (some parts are sequential); synchronisation overhead; race conditions.
Exam questions on computational thinking often ask you to apply one of these five aspects to a given scenario, e.g. "explain how abstraction was used in designing this system."
2.2 - Problem solving and programming
2.2.1 Programming techniques
Programming constructs: sequence (instructions in order), iteration (loops: for, while, do-while), branching (if/else, case/switch).
Recursion: a function that calls itself. Needs a base case (termination condition) to prevent infinite recursion. Call stack grows with each recursive call.
Variables:
Modularity: breaking a program into separate functions/procedures. Benefits: easier to test, debug, maintain and reuse. Enables parallel development by a team.
2.2.1 Use of an IDE (development tools)
An Integrated Development Environment (IDE) brings the tools needed to write, test and debug a program into one application. The spec expects you to know the main features and how each one helps the developer.
A common question is "describe two features of an IDE and how they help a programmer." Pair each feature with its benefit, e.g. "breakpoints let the programmer pause the program to inspect variable values and find where a logic error occurs."
2.2.2 Computational methods
Before choosing a technique you must work out whether a problem can be solved computationally at all, and break it down so that it can.
Once the problem is understood, these computational methods help solve it:
2.3 - Algorithms
2.3.1a Algorithm complexity: Big O notation
Big O notation describes how execution time or space grows as input size n increases. We care about the worst case and the dominant term.
| Notation | Name | Example | Notes |
|---|---|---|---|
| O(1) | Constant | Array access by index, hash table lookup | Always same time regardless of n |
| O(log n) | Logarithmic | Binary search, BST operations (balanced) | Very efficient: doubling the input adds only one extra step |
| O(n) | Linear | Linear search, traversing a linked list | Proportional to input size |
| O(n log n) | Linearithmic | Merge sort, quick sort (average) | Efficient for sorting |
| O(n²) | Polynomial/Quadratic | Bubble sort, insertion sort | Nested loops; poor for large n |
| O(2ⁿ) | Exponential | Brute force subset problems, recursive Fibonacci | Impractical for large n |
To determine Big O: identify the dominant loop structure. One loop over n = O(n). Nested loop = O(n²). Halving the problem each step = O(log n). Drop constants and lower-order terms.
2.3.1b Sorting algorithms
Best case: O(n) if already sorted (with optimisation). Simple but inefficient for large datasets.
Efficient for nearly-sorted data. Good for small datasets. Stable.
Requires O(n) extra space. Stable sort.
Worst case O(n²) if pivot consistently worst choice (sorted array with first element pivot). In-place. Not stable. Very fast in practice.
Merge sort = guaranteed O(n log n) but needs extra memory. Quick sort = faster in practice but O(n²) worst case. Bubble/insertion sort fine for small or nearly-sorted data only.
2.3.1c Search algorithms
Highly efficient, as it eliminates half the data each step.
2.3.1d Graph/tree traversal and pathfinding
Dijkstra's vs A*: Dijkstra finds shortest path to ALL nodes. A* finds shortest path to ONE target node faster by using a heuristic to prioritise promising paths.
2.3.1e Algorithms for the main data structures
The data structures themselves are covered in Paper 1 (1.4.2). The spec also expects the algorithms to add to, remove from and traverse them, shown below in the OCR reference language. Tree traversal (depth-first and breadth-first) is in the previous section.
Stack (LIFO) using an array and a top pointer. Operations: push, pop, peek, isEmpty.
Queue (FIFO) as a circular queue with front and rear pointers and a count. Operations: enqueue, dequeue, peek, isEmpty.
Linked list: each node holds data plus a pointer to the next node. Traverse by following the pointers from the head until the null pointer is reached.
Add to a linked list by creating a node and pointing the previous node's pointer at it; remove by making the previous node point past the deleted node to the one after. Big O: stack and queue push/pop are O(1); linked list search is O(n) because there is no random access.
2.2.1 - Object-oriented programming
The exam is always marked in OCR's Exam Reference Language. Switch to C# to see the same examples written in a real language. The theory (and the quiz) stays the same in both.
2.2.1 a Core OOP vocabulary you must be able to define
Object-oriented programming (OOP) models a problem as a set of objects that hold their own data and the operations that act on it. The exam tests both the theory (defining these terms) and the practice (reading and writing class code in the OCR reference language).
name, age. Declared inside the class.new keyword, which runs the constructor.new in the OCR language) that runs automatically when an object is instantiated, used to set up its attributes.Learn the one-line definitions of class, object, attribute, method, encapsulation, inheritance and polymorphism word for word. These are common 1 to 2 mark recall questions, and the mark scheme wants the keyword (e.g. "blueprint", "instance", "overrides").
2.2.1 b Defining a class: attributes, the constructor and adding methods
In the OCR Exam Reference Language a class is written between class and endclass. Inside it you declare attributes (each marked public or private) and methods (each a procedure or a function). The constructor is always a procedure called new.
Adding a new method means writing another procedure/endprocedure or function/endfunction block inside the class, before endclass. Choose function if it should hand a value back (use return), and procedure if it just does something.
private = usable only inside the class.Marks are lost if the constructor is not named new, or if attributes are not given an access modifier. Every method needs its matching endprocedure or endfunction.
2.2.1 c Writing statements to instantiate objects and call methods
To instantiate an object you assign new ClassName(arguments) to a variable. The arguments are passed to the constructor. You then use dot notation, object.method(), to run its methods.
Each new creates a separate object with its own copy of the attributes, so changing myPet has no effect on yourPet. You can also store objects in an array and loop through them:
Two things examiners look for in an instantiation answer: the new keyword, and arguments that match the constructor's parameters in order. Calling a method needs the object name, a dot, then the method name with brackets, e.g. myPet.getName().
2.2.1 d Encapsulation: private attributes with getters and setters
Encapsulation means making attributes private so outside code cannot read or change them directly, then providing getter and setter methods as the only way in. This lets the class validate changes and protects its data from being put into an invalid state.
Outside the class you must go through these methods. myPet.setAge(4) is allowed; trying to reach the data directly with myPet.age = 4 would fail because age is private.
If asked why encapsulation is "good practice", say: it protects data integrity through validation, hides internal detail (abstraction), and makes the program easier to maintain because each class controls its own data.
2.2.1 e Inheritance: reusing a class with inherits and super
Inheritance lets a new class take on the attributes and methods of an existing one. Write class Child inherits Parent. Inside the child's constructor, super.new(...) calls the parent's constructor so inherited attributes are set up correctly, then the child adds its own.
A Dog object now has everything a Pet has plus its own breed:
Inheritance models an "is-a" relationship (a Dog is a Pet). Do not confuse it with composition ("has-a"), where an object holds other objects as attributes, e.g. a Car has an Engine. The keyword is inherits, and super reaches the parent class.
2.2.1 f Polymorphism and method overriding
Polymorphism means "many forms". A subclass can override an inherited method by defining its own version with the same name. The same method call then produces different behaviour depending on which class the object belongs to.
The same line a.speak() runs different code each time because the object decides which version applies. That is polymorphism in action.
Overriding (a subclass redefining an inherited method with the same name) is the form of polymorphism the exam expects. The benefit: you can treat different object types uniformly through one shared method name, which keeps code flexible and extensible.
2.2.1 g Advantages of OOP (and when it suits a problem)
A balanced answer also notes drawbacks: OOP adds complexity and can be overkill for small, simple programs, and there can be a slight performance overhead. For tiny scripts a procedural approach may be quicker to write.
2.2.1 h OOP syntax cheat sheet
| You want to... | OCR reference language |
|---|---|
| Define a class | class Pet ... endclass |
| Declare a private attribute | private name |
| Declare a public attribute | public score |
| Write the constructor | public procedure new(...) ... endprocedure |
| Add a value-returning method | public function getName() ... return name ... endfunction |
| Add an action method | public procedure birthday() ... endprocedure |
| Instantiate an object | myPet = new Pet("Rex", 3) |
| Call a method | myPet.getName() |
| Inherit from a class | class Dog inherits Pet |
| Call the parent constructor | super.new(...) |
| You want to... | C# |
|---|---|
| Define a class | class Pet { ... } |
| Declare a private attribute | private string name; |
| Declare a public attribute | public int score; |
| Write the constructor | public Pet(...) { ... } (named after the class) |
| Add a value-returning method | public string GetName() { return name; } |
| Add an action method | public void Birthday() { ... } |
| Instantiate an object | Pet myPet = new Pet("Rex", 3); |
| Call a method | myPet.GetName(); |
| Inherit from a class | class Dog : Pet |
| Call the parent constructor | : base(...) after the constructor |
OCR's reference language has no separate "override" keyword: you override simply by redefining a method of the same name in the subclass. Constructors are always called new, and there is no destructor.
2.2.1 i Test yourself: interactive OOP quiz
Ten questions covering vocabulary, syntax and code reading. Pick an answer to see why it is right or wrong, then move on.