An original Thinka practice paper modelled on the structure and difficulty of the Jun 2024 Cambridge OCR AS Level Computer Science - H046 paper. Not affiliated with or reproduced from Cambridge.
PastPaper.section H046/01: Computing Principles
Answer all questions. Calculators must not be used. Structured write-ups require level-of-response evaluations for extended questions.
13 PastPaper.question · 60 PastPaper.marks
PastPaper.question 1 · Short Answer
3 PastPaper.marks
Simplify the Boolean expression \(\neg(A \lor B) \lor (\neg A \land B)\) using Boolean identities. Show your working.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
First, apply De Morgan's Law to \(\neg(A \lor B)\) to get \(\neg A \land \neg B\). Substituting this back into the original expression yields \((\neg A \land \neg B) \lor (\neg A \land B)\). Next, apply the Distributive Law to factor out \(\neg A\), resulting in \(\neg A \land (\neg B \lor B)\). Since \(\neg B \lor B\) is a tautology (always equal to 1), the expression simplifies to \(\neg A \land 1\), which is equivalent to \(\neg A\).
PastPaper.markingScheme
1 mark for correctly applying De Morgan's Law to get \(\neg A \land \neg B\). 1 mark for applying the Distributive Law to get \(\neg A \land (\neg B \lor B)\). 1 mark for simplifying \(\neg A \land 1\) to the final correct expression \(\neg A\).
PastPaper.question 2 · Short Answer
3 PastPaper.marks
Describe three differences between paging and segmentation as virtual memory management techniques.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Paging is a physical division mechanism where memory is divided into fixed-size units called pages. Segmentation is a logical division mechanism where programs are split into variable-sized units (segments) that reflect the program structure (such as methods or modules). Because page sizes are fixed, a process may not occupy the whole of its last page, causing internal fragmentation. Since segments are of variable sizes, gaps can open up between segments in physical memory, leading to external fragmentation.
PastPaper.markingScheme
Award 1 mark per valid comparative point, up to a maximum of 3 marks: - 1 mark: Paging splits memory into fixed-sized blocks, while segmentation splits memory into variable-sized blocks based on logical components. - 1 mark: Paging is entirely managed by the OS/hardware and is invisible to the programmer, while segmentation matches the logical structure of program code and can be visible to the programmer. - 1 mark: Paging can cause internal fragmentation (wasted space within a page), whereas segmentation can cause external fragmentation (unusable free space between allocated segments).
PastPaper.question 3 · Short Answer
3 PastPaper.marks
Convert the denary number \(-37\) into an 8-bit two's complement binary integer. Show your working.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
1. Represent positive 37 in binary: \(32 + 4 + 1 = 00100101_2\). 2. Invert all the bits to get the one's complement: \(00100101_2 \rightarrow 11011010_2\). 3. Add 1 to the result to get the two's complement: \(11011010_2 + 1 = 11011011_2\). Verification: \(-128 + 64 + 16 + 8 + 2 + 1 = -37\).
PastPaper.markingScheme
1 mark for correctly showing positive 37 in 8-bit binary: \(00100101\). 1 mark for showing a correct conversion process (either inverting the bits to \(11011010\) or subtracting 37 from 256 to get 219). 1 mark for the correct final 8-bit two's complement representation: \(11011011\).
PastPaper.question 4 · Trace
3 PastPaper.marks
Consider the following pseudocode segment:
x = 3 y = 7 total = 0 while x < y total = total + x * 2 x = x + 1 endwhile
Determine the final values of 'x' and 'total' after the pseudocode finishes execution. Show your trace or working.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Trace of the loop iterations: - Initial state: x = 3, y = 7, total = 0 - Iteration 1: x < y (3 < 7) is true. total = 0 + (3 * 2) = 6. x is incremented to 4. - Iteration 2: x < y (4 < 7) is true. total = 6 + (4 * 2) = 14. x is incremented to 5. - Iteration 3: x < y (5 < 7) is true. total = 14 + (5 * 2) = 24. x is incremented to 6. - Iteration 4: x < y (6 < 7) is true. total = 24 + (6 * 2) = 36. x is incremented to 7. - Iteration 5: x < y (7 < 7) is false. Loop terminates. Final values: x = 7, total = 36.
PastPaper.markingScheme
1 mark for showing correct trace values for intermediate states of 'total' (such as 6, 14, 24). 1 mark for the correct final value of x = 7. 1 mark for the correct final value of total = 36.
PastPaper.question 5 · Short Answer
3 PastPaper.marks
Describe the role of the Program Counter (PC) register during the Fetch stage of the Fetch-Decode-Execute cycle, explaining how its value changes.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
The Program Counter (PC) is a dedicated CPU register that tracks instruction execution. During the Fetch stage, the PC's current value (an address) is copied over the internal bus to the Memory Address Register (MAR) to initiate the memory read. Simultaneously, or immediately after, the PC's value is incremented by 1 (or the instruction size) to prepare for the subsequent cycle.
PastPaper.markingScheme
1 mark for identifying that the Program Counter (PC) holds the address of the next instruction to be fetched. 1 mark for describing that this address is copied to the Memory Address Register (MAR) at the start of the cycle. 1 mark for explaining that the PC is incremented (by 1) to point to the next instruction in sequence.
PastPaper.question 6 · Medium Structured Logic
4.5 PastPaper.marks
A CPU scheduler uses Round Robin (RR) scheduling with a time quantum of 4 ms. Three processes, P1, P2, and P3, arrive at time 0 in that order. P1 requires 7 ms of CPU time, P2 requires 3 ms, and P3 requires 5 ms. Context switching overhead is negligible. Trace the execution order of these processes, state their exact completion times, and calculate the overall average waiting time for the three processes.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
1. Trace execution sequence: Time 0 to 4: P1 runs (3 ms remaining). Queue becomes [P2, P3, P1]. Time 4 to 7: P2 runs (0 ms remaining) and completes. Queue becomes [P3, P1]. Time 7 to 11: P3 runs (1 ms remaining). Queue becomes [P1, P3]. Time 11 to 14: P1 runs (0 ms remaining) and completes. Queue becomes [P3]. Time 14 to 15: P3 runs (0 ms remaining) and completes. 2. Record completion times: P1 completes at 14 ms, P2 completes at 7 ms, and P3 completes at 15 ms. 3. Calculate waiting times: Waiting time = Completion time - Arrival time - Burst time. P1 wait time: 14 - 0 - 7 = 7 ms. P2 wait time: 7 - 0 - 3 = 4 ms. P3 wait time: 15 - 0 - 5 = 10 ms. 4. Calculate average waiting time: \((7 + 4 + 10) / 3 = 21 / 3 = 7\) ms.
PastPaper.markingScheme
1 mark for identifying the correct completion times for P1 (14 ms) and P2 (7 ms). 1 mark for identifying the correct completion time for P3 (15 ms). 1.5 marks for calculating individual waiting times correctly (P1 = 7 ms, P2 = 4 ms, P3 = 10 ms; deduct 0.5 marks for each error). 1 mark for showing the correct working and concluding with the correct average waiting time of 7 ms.
PastPaper.question 7 · Medium Structured Logic
4.5 PastPaper.marks
Simplify the following Boolean expression using Boolean algebra laws, showing each step of your working and stating the name of the identity or law used: \( A \cdot B + A \cdot (B + C) + B \cdot (B + C) \)
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Step 1: Expand brackets using the Distributive Law: \( A \cdot B + A \cdot B + A \cdot C + B \cdot B + B \cdot C \). Step 2: Apply the Idempotent Law where \( A \cdot B + A \cdot B = A \cdot B \) and \( B \cdot B = B \), simplifying the expression to: \( A \cdot B + A \cdot C + B + B \cdot C \). Step 3: Apply the Absorption Law where \( B + B \cdot C = B \), reducing the expression to: \( A \cdot B + A \cdot C + B \). Step 4: Apply the Absorption Law again where \( B + A \cdot B = B \) (by rearranging to \( B + B \cdot A + A \cdot C \)), yielding the final simplified expression: \( B + A \cdot C \).
PastPaper.markingScheme
1 mark for correctly expanding all brackets to yield \( A \cdot B + A \cdot B + A \cdot C + B \cdot B + B \cdot C \). 1 mark for applying the Idempotent Law to reduce repeating terms. 1 mark for applying the Absorption Law to simplify \( B + B \cdot C \) to \( B \). 1 mark for applying the Absorption Law to simplify \( B + A \cdot B \) to \( B \). 0.5 marks for the correct final simplified expression \( B + A \cdot C \) (or equivalent form like \( B + AC \)).
PastPaper.question 8 · Medium Structured Logic
4.5 PastPaper.marks
A computer architecture executes instructions using the Fetch-Decode-Execute cycle. The Program Counter (PC) currently holds the memory address \( 0\text{x}3\text{A} \). The instruction stored at memory address \( 0\text{x}3\text{A} \) is \( \text{ADD } 0\text{x}4\text{F} \). Describe step-by-step how the Program Counter (PC), Memory Address Register (MAR), Memory Data Register (MDR), and Current Instruction Register (CIR) change states during the Fetch phase of this instruction cycle.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Step 1: The address in the PC (\( 0\text{x}3\text{A} \)) is copied to the Memory Address Register (MAR) via the Address Bus. Step 2: The Program Counter (PC) is incremented by 1 to point to the next instruction address (\( 0\text{x}3\text{B} \)). Step 3: A read signal is sent to memory, and the instruction stored at the address in the MAR (\( 0\text{x}3\text{A} \)) is loaded into the Memory Data Register (MDR) via the Data Bus. The MDR now holds the instruction value \( \text{ADD } 0\text{x}4\text{F} \). Step 4: The contents of the MDR are copied to the Current Instruction Register (CIR) so that they can be decoded in the next phase of the cycle.
PastPaper.markingScheme
1 mark for stating that the value of the PC (\( 0\text{x}3\text{A} \)) is copied to the MAR. 1 mark for stating that the PC is incremented to hold the next address (\( 0\text{x}3\text{B} \)). 1 mark for stating that the instruction is fetched from memory at the address held in the MAR and loaded into the MDR. 1 mark for stating that the instruction is copied from the MDR to the CIR. 0.5 marks for specifying the correct registers and direction of data transfer (e.g., using buses or correct direction of data copying).
PastPaper.question 9 · Medium Structured Logic
4.5 PastPaper.marks
A compiler processes high-level code statements into machine code. For the source code statement: `total = subtotal * 1.20`, explain the different actions and outputs produced during the Lexical Analysis stage and the Syntax Analysis stage.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
During Lexical Analysis: 1. Unnecessary whitespaces, formatting characters, and comments are removed from the statement. 2. The code is broken down into a series of lexemes which are converted into tokens: e.g., identifier (total), operator (=), identifier (subtotal), operator (*), real literal (1.20). 3. Identifiers are added to the Symbol Table along with details like scope and type. During Syntax Analysis: 1. The stream of tokens is checked against the grammar rules of the programming language. 2. A parse tree (or abstract syntax tree) is constructed to model the logical hierarchical structure of the operation (ensuring operator precedence, such as multiplication occurring before assignment, is preserved). 3. Any syntax errors are generated if rules are broken.
PastPaper.markingScheme
1 mark for explaining tokenisation during Lexical Analysis (with reference to the identifiers, operators, or literals in the statement). 1 mark for mentioning the removal of comments/whitespace and the creation of entries in the Symbol Table. 1 mark for describing that Syntax Analysis checks the sequence of tokens against the language rules. 1 mark for describing the creation of a parse tree / abstract syntax tree. 0.5 marks for correctly applying these phases to the specific code example provided.
PastPaper.question 10 · Medium Structured Logic
4.5 PastPaper.marks
An HTML document contains the element: `
Welcome to our site.
`. The associated CSS stylesheet has rules: `div p { color: green; }`, `#container .alert-text { color: red; }`, and `#highlight { color: orange; }`. Explain which color will actually be applied to the text, and justify your answer by analyzing the rules of CSS specificity and cascading order.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
The final text color applied will be blue. Justification: 1. The paragraph element contains an inline style attribute: `style="color: blue;"`. 2. Inline styles always take precedence over rules defined in external or internal stylesheets, regardless of the specificity of those stylesheet selectors. 3. If inline styles were not present, we would calculate selector specificity: `div p` has specificity (0,0,0,2); `#highlight` has specificity (0,1,0,0); `#container .alert-text` has specificity (0,1,1,0). `#container .alert-text` would have won due to having higher specificity (1 ID, 1 class) than `#highlight` (1 ID). However, the inline style overrides all of these.
PastPaper.markingScheme
0.5 marks for identifying the correct final color (blue). 1 mark for explaining that inline styles defined on HTML elements directly override declarations in external/internal stylesheets. 1 mark for identifying that `#container .alert-text` has a specificity of 1 ID and 1 class (0,1,1,0). 1 mark for identifying that `#highlight` has a specificity of 1 ID (0,1,0,0). 1 mark for identifying that `div p` has a specificity of 2 element selectors (0,0,0,2).
PastPaper.question 11 · Medium Structured Logic
4.5 PastPaper.marks
A normalized real number is stored in binary using an 8-bit mantissa and a 4-bit exponent, both represented in Two's Complement. The binary representation is: Mantissa: `0.1011000`, Exponent: `0011`. Convert this representation into its denary equivalent, showing each step of your calculation.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Step 1: Convert the exponent. The exponent is `0011`. Since the most significant bit (MSB) is 0, it is a positive integer. Value = \( 2^1 + 2^0 = 2 + 1 = 3 \). Step 2: Convert the mantissa. The mantissa is `0.1011000`. It is a positive normalized fraction. The place values are: \( 0.1 \) (value 0.5), \( 0.00 \) (value 0), \( 0.001 \) (value 0.125), \( 0.0001 \) (value 0.0625). Total value of mantissa = \( 0.5 + 0.125 + 0.0625 = 0.6875 \). Step 3: Combine mantissa and exponent. Multiply the mantissa by \( 2^{\text{exponent}} \): \( 0.6875 \times 2^3 = 0.6875 \times 8 = 5.5 \). Alternatively, shift the binary point 3 places to the right: `0.1011000` becomes `101.1000` in binary, which evaluates to \( 4 + 1 + 0.5 = 5.5 \) in denary.
PastPaper.markingScheme
1 mark for correctly converting the exponent `0011` to the denary value of 3. 1 mark for showing correct working to convert the mantissa `0.1011000` to denary (0.6875 or 11/16). 1 mark for showing the correct multiplication step (\( 0.6875 \times 2^3 \)) or equivalent correct binary point shift of 3 places. 1 mark for explaining that the MSBs of both the mantissa and exponent indicate they are positive values. 0.5 marks for arriving at the correct final denary answer of 5.5 (or 5 1/2).
PastPaper.question 12 · Extended Evaluation
9 PastPaper.marks
An engineering firm is designing a real-time autopilot control system for an autonomous passenger drone. The development team is debating whether to use a compiled language (such as C++) or an interpreted language (such as Python) to build the core navigation and flight-control software. Evaluate the suitability of both compilation and interpretation for this specific system, and recommend which translation method should be chosen. Your evaluation should consider execution speed, safety-critical error detection, resource constraints, and development workflow.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Compilation translates the entire high-level source code into machine-executable binary code all at once before execution. Interpretation translates and runs code line-by-line at runtime. 1. Execution Speed: Real-time autopilot systems must process inputs (e.g., wind changes, sensor feeds) and output physical flight adjustments instantly with predictable latency. Compiled code runs directly on the CPU without translation overhead, ensuring consistent sub-millisecond responses. Interpreted code is much slower and less predictable due to translation occurring during runtime. 2. Safety-Critical Error Detection: Autonomous passenger drones require rigorous safety standards. Compilers perform extensive ahead-of-time semantic and syntactic analysis, catching type mismatches, variable scope errors, and syntax errors before the program is compiled. An interpreted language might only discover a syntax error in a critical situation (e.g., when trying to execute an emergency landing routine), which could cause a sudden system crash. 3. Resource Constraints: Onboard computers have strict weight, size, and power limitations. Compiled programs run as lightweight, standalone executables. Interpreted programs require the interpreter software to run continuously, consuming extra processing power and system memory. 4. Development Workflow: While interpreters allow rapid prototyping and interactive testing, this benefit is vastly outweighed by the safety-critical constraints. The final deployment must use a compiled language to ensure flight safety.
PastPaper.markingScheme
Level 3 (7-9 marks): Shows a comprehensive and detailed evaluation of both compiled and interpreted approaches, explicitly applied to the real-time passenger drone scenario. Accurately links technical concepts (e.g., execution speed, ahead-of-time syntax checking, resource footprints) to safety-critical real-world impacts. Formulates a logical, fully justified recommendation for compilation. Level 2 (4-6 marks): Compares compilers and interpreters with some accurate technical depth. Attempts to relate the characteristics to the drone scenario, though the discussion may focus heavily on one aspect (e.g., speed) while neglecting others (e.g., runtime error risk). Suggests a recommendation with basic justification. Level 1 (1-3 marks): Outlines basic definitions of compilers and interpreters. Little or no application to the drone autopilot scenario, or presents a weak, unsupported recommendation.
PastPaper.question 13 · Extended Evaluation
9 PastPaper.marks
A software company is developing a new operating system designed specifically for high-performance virtual reality (VR) headsets. The headset has strict memory limits but must run multiple highly-interactive tasks concurrently (such as rendering, spatial audio processing, and motion tracking). Evaluate the use of paging versus segmentation as virtual memory management techniques for this virtual reality operating system, and recommend which approach is more appropriate.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Memory management is critical to ensure that a high-performance VR operating system runs smoothly without latency spikes. 1. Paging: Paging divides physical memory and virtual memory into fixed-size blocks (pages and frames). Because blocks are fixed and uniform, virtual pages can be mapped non-contiguously to any free physical page frames. This completely eliminates external fragmentation. It prevents the need for memory compaction (defragmentation), which is computationally expensive and introduces highly undesirable latency spikes that cause motion-sickness in VR. However, paging can cause small amounts of internal fragmentation if processes do not perfectly fill their last page. 2. Segmentation: Segmentation divides memory into variable-sized, logically cohesive segments (such as modules, library functions, or data stacks). This matches the programmer's logical view of memory and simplifies features like read/write sharing (e.g., sharing a massive 3D texture across rendering threads). However, because segments are variable in size, allocating and deallocating them over time leads to external fragmentation. Over time, the operating system must run compaction routines to merge free spaces, pausing critical VR loops and ruining the real-time rendering performance. 3. Recommendation: A purely paged system (or a hybrid paged-segmentation system) is far more appropriate. Given the strict timing constraints of VR rendering (which must hit 90+ frames per second consistently), the absolute predictability and lack of external fragmentation provided by paging outweigh the logical benefits of segmentation.
PastPaper.markingScheme
Level 3 (7-9 marks): Demonstrates a highly detailed and clear understanding of paging (fixed-size, physical allocation, no external fragmentation) and segmentation (variable-size, logical allocation, suffers from external fragmentation). Strongly applies these concepts to the specific requirements of VR (e.g., latency, real-time rendering, avoiding frame drops). Recommends and justifies an approach with logical, technically-sound reasoning. Level 2 (4-6 marks): Compares paging and segmentation with some technical accuracy, noting the difference in sizing and fragmentation. Makes some connection to the VR context (e.g., speed or memory limits) but may lack depth on how external fragmentation compaction affects latency. Suggests a logical recommendation. Level 1 (1-3 marks): Identifies basic differences between paging and segmentation. Contains superficial comparison or confusion between terms. No meaningful application to VR or recommendation is provided.
PastPaper.section H046/02: Algorithms and problem solving
Answer all questions. Pseudocode or programming language syntax may be used to develop algorithmic solutions.
16 PastPaper.question · 64 PastPaper.marks
PastPaper.question 1 · Short Answer & Definition
2.5 PastPaper.marks
Define the terms 'abstraction by representation' and 'abstraction by generalisation', and state the key difference between them in terms of how they handle details.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Abstraction by representation involves removing unnecessary details to leave only the essential features needed to solve a specific problem. Abstraction by generalisation involves grouping common characteristics of similar concrete objects to create a single, representative general concept or class. The key difference is that representation strips details from a single context, whereas generalisation groups similarities across multiple different entities.
PastPaper.markingScheme
1 mark: Correct definition of abstraction by representation (focusing on hiding irrelevant details for the task). 1 mark: Correct definition of abstraction by generalisation (focusing on grouping common traits to form a general concept/class). 0.5 marks: Stating the key distinction (representation reduces details of a single entity, generalisation groups similarities across multiple entities).
PastPaper.question 2 · Short Answer & Definition
2.5 PastPaper.marks
A developer wants to search for a specific integer in an array of 500 unsorted integers. Explain why a binary search algorithm cannot be directly applied to this array, and describe the pre-processing step required, including its impact on efficiency.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
A binary search requires the dataset to be sorted so that the middle element can be used to discard half of the remaining data at each step. If the array is unsorted, this logic fails. The pre-processing step required is to sort the array using a sorting algorithm (e.g., merge sort or insertion sort). The impact on efficiency is that sorting introduces a significant computational overhead (e.g., \(O(N \log N)\) or \(O(N^2)\)), which may make the overall process slower than a single linear search if the search is only performed once.
PastPaper.markingScheme
1 mark: Explaining that binary search requires sorted data to decide which half to discard. 1 mark: Specifying that the array must first be sorted. 0.5 marks: Explaining the negative efficiency impact of sorting (computational overhead) if searching only a small number of times.
PastPaper.question 3 · Short Answer & Definition
2.5 PastPaper.marks
Explain the difference between local variables and global variables, and describe why using local variables is considered good programming practice.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Local variables are declared inside a subroutine, are only accessible within that subroutine, and are destroyed when the subroutine finishes execution. Global variables are declared in the main program, can be accessed throughout the entire program, and exist for the duration of the program's run. Local variables are good practice because they prevent accidental changes to data from other parts of the program (encapsulation), make subroutines reusable, and save memory.
PastPaper.markingScheme
1 mark: Correctly defining local variables (limited scope/lifetime). 1 mark: Correctly defining global variables (global scope/lifetime). 0.5 marks: Describing a valid reason why local variables represent good practice (e.g., avoidance of side effects, memory management, modularity).
PastPaper.question 4 · Short Answer & Definition
2.5 PastPaper.marks
State two advantages of implementing a queue as a circular queue rather than a linear queue using a static array of fixed size, and explain how a circular queue identifies that it is empty.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
The first advantage is memory efficiency, as circular queues reuse empty array spaces at the front that are freed up when items are dequeued. The second advantage is that it avoids the need to shift remaining elements forward upon dequeuing, which saves execution time. A circular queue identifies that it is empty when its front pointer and rear pointer point to the same index (or are set to a defined sentinel value).
PastPaper.markingScheme
1 mark: Stating first advantage (reuses memory slots / prevents false queue full error). 1 mark: Stating second advantage (avoids shifting elements). 0.5 marks: Stating that the front and rear pointers pointing to the same location (or equivalent sentinel value) signifies an empty queue.
PastPaper.question 5 · Short Answer & Definition
2.5 PastPaper.marks
In the context of software development, state what is meant by a 'precondition' for a subroutine, and give an example of a precondition that might be defined for a subroutine called calculateSquareRoot(number).
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
A precondition is a constraint or requirement that must be true before a subroutine is executed to ensure correct functionality and prevent errors. For calculateSquareRoot(number), a precondition is that the parameter 'number' must be greater than or equal to 0 (non-negative).
PastPaper.markingScheme
1 mark: Defining precondition (constraint required to be true before execution). 0.5 marks: Explaining its purpose (prevents runtime errors or reduces validation inside the subroutine). 1 mark: Valid precondition example for calculateSquareRoot (e.g., number >= 0).
PastPaper.question 6 · Short Answer & Definition
2.5 PastPaper.marks
Describe the process of 'stepwise refinement' (top-down design) and explain why this process is useful when designing complex algorithms.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
Stepwise refinement involves breaking down a large, complex problem into smaller, simpler sub-problems, and repeating this process until each sub-problem is basic enough to be implemented as a single modular subroutine. This process is useful because it simplifies the design of complex systems, allows different team members to program different modules concurrently, and makes debugging and testing much easier.
PastPaper.markingScheme
1 mark: Describing the decomposition of a large problem into smaller sub-problems. 1 mark: Describing the iterative nature of breaking tasks down to modular levels. 0.5 marks: Stating a valid benefit of this approach (e.g., concurrent development, simplified testing, modularity).
PastPaper.question 7 · Short Answer & Definition
2.5 PastPaper.marks
Explain how a standard Bubble Sort algorithm can be optimized to stop early, and describe the variable required to implement this optimization.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
The Bubble Sort algorithm can be optimized by checking if a full pass is completed without making any swaps; if no swaps occur, the list is already sorted and the algorithm can stop. This optimization is implemented using a boolean flag variable (e.g., 'swapped') which is set to False at the start of each pass, changed to True if a swap occurs, and checked at the end of each pass to determine whether to terminate.
PastPaper.markingScheme
1 mark: Explaining early termination when a pass completes with zero swaps. 0.5 marks: Specifying that a boolean flag variable is required. 1 mark: Describing the logic of initializing, updating, and testing the boolean flag.
PastPaper.question 8 · Short Answer & Definition
2.5 PastPaper.marks
State the difference between a 'condition-controlled loop' and a 'count-controlled loop', and explain how the decision-making process differs between them during execution.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
A condition-controlled loop repeats instructions based on a boolean condition being true or false, and the number of iterations is not known beforehand. A count-controlled loop repeats instructions a predetermined, fixed number of times using a counter. During execution, a condition-controlled loop evaluates a boolean expression at the start or end of each iteration, whereas a count-controlled loop increments/decrements a counter and checks if it has reached its target value.
PastPaper.markingScheme
1 mark: Defining condition-controlled loops (runs based on boolean expression, variable iterations). 1 mark: Defining count-controlled loops (runs fixed times using a counter). 0.5 marks: Explaining the execution decision difference (boolean expression evaluation vs counter comparison against target).
Write a pseudocode function named `findMinIndex` that takes a 1D array of integers, `arr`, as a parameter and returns the index of the first occurrence of the minimum value in the array.
You should assume that: * The array is 0-indexed and contains at least one element. * You can obtain the size of the array using `arr.length`.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
To find the index of the first minimum value: 1. Start by assuming that the element at index 0 is the minimum, so initialize `minIndex` to 0. 2. Loop through the array starting from index 1 up to the last index (`arr.length - 1`). 3. In each iteration, compare the current element `arr[i]` with the element at our current minimum index `arr[minIndex]`. 4. If `arr[i]` is strictly less than `arr[minIndex]`, update `minIndex` to `i`. Using `<` instead of `<=` ensures that we keep the first occurrence in case there are multiple identical minimum values. 5. After the loop completes, return `minIndex`.
PastPaper.markingScheme
1 mark: Correct function header with parameter (e.g., `function findMinIndex(arr)`). 1 mark: Initializing a tracking variable for the index of the minimum element to 0 (e.g., `minIndex = 0`). 1 mark: Correct loop bounds iterating from 1 to `arr.length - 1`. 1 mark: Correct comparison structure checking if `arr[i] < arr[minIndex]` (must be strictly less than to retrieve the first occurrence). 1 mark: Correctly updating the tracking variable and returning `minIndex` at the end of the function.
The following pseudocode algorithm is intended to calculate the average of all positive integers (integers strictly greater than 0) in a 1D array of integers named `numbers`.
``` 1: function averagePositives(numbers) 2: sum = 0 3: count = 1 4: for i = 0 to numbers.length 5: if numbers[i] > 0 then 6: sum = sum + i 7: count = count + 1 8: endif 9: next i 10: return sum / count 11: endfunction ```
There are three logical errors in this algorithm. Identify the line number for each error, explain why it is an error, and write the corrected line of pseudocode.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
1. Line 3: `count` is initialized to 1 instead of 0. This means the divisor in the average calculation will always be 1 greater than the actual count of positive numbers, resulting in an incorrect lower average. 2. Line 4: In a 0-indexed array, the maximum index is `numbers.length - 1`. Iterating to `numbers.length` results in an 'index out of bounds' exception. 3. Line 6: `sum = sum + i` adds the loop index variable `i` instead of the value stored in the array at that index, which is `numbers[i]`.
PastPaper.markingScheme
1 mark: Identify Line 3 as error and state corrected line: `count = 0` (or equivalent). 2 marks: Identify Line 4 as error, explain that it causes an out-of-bounds error on 0-indexed arrays, and state corrected line: `for i = 0 to numbers.length - 1`. 2 marks: Identify Line 6 as error, explain that it incorrectly sums the loop index instead of the array element, and state corrected line: `sum = sum + numbers[i]`.
A stack data structure is implemented using a static 1D array named `stackArray` of size 50 (indices 0 to 49). An integer variable `topPointer` stores the array index of the current top item. When the stack is empty, `topPointer` is equal to -1.
Write a pseudocode procedure `push` that takes an integer `newItem` as a parameter and attempts to add it to the stack. If the stack is full, it must output 'Stack Overflow'. Otherwise, it must update the pointer and add the item.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
A stack is a Last-In, First-Out (LIFO) structure. When pushing onto a static stack: 1. We must check if the stack is already full. Since the maximum index is 49, the stack is full when `topPointer` is equal to 49. 2. If it is full, output 'Stack Overflow'. 3. If it is not full, we increment `topPointer` by 1 to point to the next free slot. 4. We then assign `newItem` to `stackArray[topPointer]`.
PastPaper.markingScheme
1 mark: Correct procedure header with parameter (e.g. `procedure push(newItem)`). 1 mark: Check if stack is full by testing if `topPointer` is 49 (or equivalent check, e.g. `topPointer >= 49`). 1 mark: Output/print 'Stack Overflow' message if full. 1 mark: Increment `topPointer` by 1 inside the `else` clause. 1 mark: Store `newItem` in `stackArray` at index `topPointer`.
The following incomplete pseudocode is designed to perform a bubble sort in ascending order on a 1D array of integers named `items` of size `n` (indices 0 to `n - 1`).
``` 1: procedure bubbleSort(items, n) 2: for i = 0 to n - 2 3: for j = 0 to n - i - 2 4: // Code for lines 4 to 8 is missing 5: 6: 7: 8: 9: next j 10: next i 11: endprocedure ```
Write the five missing lines (lines 4 to 8) to complete the bubble sort algorithm.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
During a bubble sort iteration, adjacent elements are compared. Since we are sorting in ascending order, if the element at index `j` is larger than the element at `j + 1`, we swap them using a temporary storage variable `temp`. Line 4: Compare adjacent items: `if items[j] > items[j + 1] then` Line 5: Store the first item: `temp = items[j]` Line 6: Replace the first item with the second item: `items[j] = items[j + 1]` Line 7: Place the stored first item into the second item's position: `items[j + 1] = temp` Line 8: Close the selection block: `endif`
PastPaper.markingScheme
1 mark: Line 4 comparison: `if items[j] > items[j + 1] then` (or equivalent logical comparison for ascending order). 1 mark: Line 5: Store one of the items in a temporary variable (e.g., `temp = items[j]`). 1 mark: Line 6: Correct assignment of the other element to the first's index (e.g., `items[j] = items[j + 1]`). 1 mark: Line 7: Correct assignment of the temporary variable to the second element (e.g., `items[j + 1] = temp`). 1 mark: Line 8: Close selection structure using `endif` (or equivalent).
A car rental company calculates daily rental cost based on the number of kilometres driven by the customer. The pricing tier is as follows: * The first 100 kilometres are charged at a rate of £0.25 per kilometre. * Any distance beyond 100 kilometres is charged at £0.15 per kilometre. * All rentals have a flat administration fee of £15.00 added to the final bill.
Write a pseudocode function `calculateRentalCost` that takes a real number `km` (the number of kilometres driven) as a parameter and returns the total rental cost. You can assume that `km` is always greater than 0.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
To implement this tiered pricing: 1. Use an `if` statement to check if `km <= 100`. If so, calculate the cost purely by multiplying `km * 0.25`. 2. In the `else` block (when `km > 100`), calculate the cost of the first 100 km as `100 * 0.25` (which is 25) and add it to the cost of the remaining distance: `(km - 100) * 0.15`. 3. Finally, add the flat administration fee of £15.00 to the calculated cost and return the result.
PastPaper.markingScheme
1 mark: Correct function header with parameter (e.g. `function calculateRentalCost(km)`). 1 mark: Conditional check dividing the two pricing tiers (`if km <= 100` or equivalent logic). 1 mark: Correct calculation for distance up to 100 km (e.g. `cost = km * 0.25`). 1 mark: Correct calculation for distance greater than 100 km (e.g. `cost = 25 + (km - 100) * 0.15`). 1 mark: Add £15.00 administration fee and correctly return final cost.
A system requires passwords to meet certain safety criteria. The pseudocode function below is designed to validate a password. A password is valid if and only if it is: 1. At least 8 characters long. 2. Contains at least one exclamation mark (`!`). 3. Does NOT contain any space characters (` `).
``` 1: function isValid(password) 2: if password.length < 8 then 3: return false 4: endif 5: hasExclamation = false 6: hasSpace = false 7: for i = 0 to password.length - 1 8: char = password.substring(i, 1) // returns 1 character starting at index i 9: if char == \"!\" then 10: hasExclamation = true 11: endif 12: if char == \" \" then 13: hasSpace = true 14: endif 15: next i 16: return hasExclamation and hasSpace 17: endfunction ```
(a) Identify the logical error on Line 16 of the pseudocode and write the corrected line. (2 marks) (b) Explain why a password of `\"Secure!Pass\"` would return `false` in the original buggy algorithm. (2 marks) (c) State the boolean value returned by the original buggy algorithm if the input is `\"Secure Pass!\"`. (1 mark)
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
(a) Line 16 currently returns `hasExclamation and hasSpace`. This logic is inverted for the space requirement, because a valid password should NOT contain spaces. The corrected line is `return hasExclamation and not hasSpace`. (b) The password `"Secure!Pass"` contains an exclamation mark, which successfully flags `hasExclamation = true`. However, it does not contain a space, leaving `hasSpace = false`. Because the buggy code checks for `hasExclamation and hasSpace` (meaning both must be true), it performs the evaluation `true and false`, resulting in `false` being returned. (c) The input `"Secure Pass!"` is 12 characters long, contains a space, and contains an exclamation mark. Therefore, both `hasExclamation` and `hasSpace` are set to `true`. Line 16 evaluates `true and true`, returning `true`.
PastPaper.markingScheme
(a) 1 mark for identifying that the return statement requires `hasSpace` to be true instead of false. 1 mark for correcting the line to `return hasExclamation and not hasSpace` (or equivalent statement using `not` or `== false`). (b) 1 mark for stating that `hasSpace` is evaluated as `false` since there is no space in 'Secure!Pass'. 1 mark for stating that the boolean evaluation `true and false` results in `false`. (c) 1 mark for stating `true` (or `TRUE`).
Write a pseudocode function named `linearSearch` that searches a 1D array of strings named `arr` for a target string named `target`.
The function should return the index of the element if found. If the element is not found, the function must return -1.
You should assume the array indices start at 0 and the size of the array can be found using `arr.length`.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
A linear search checks each element of an array sequentially: 1. Define the function with two parameters: `arr` (the array) and `target` (the string we are searching for). 2. Set up a `for` loop that iterates from `0` to the last index of the array, which is `arr.length - 1`. 3. Inside the loop, check if the current item `arr[i]` is equal to `target`. 4. If it is equal, return the current index `i` immediately, exiting the function. 5. If the loop completes and no match has been found, return `-1` outside the loop.
PastPaper.markingScheme
1 mark: Correct function header with parameters (e.g., `function linearSearch(arr, target)`). 1 mark: Loop iterating from `0` to `arr.length - 1` (allowing sequential check of all elements). 1 mark: Correct conditional statement to check if element matches target (e.g., `if arr[i] == target then` or equivalent). 1 mark: Return the current index `i` inside the conditional block. 1 mark: Return `-1` outside of the loop to signify that the element was not found.
A school's administrative system stores a collection of student IDs in an unsorted 1D array. Due to a system error, some duplicate IDs have been entered.
An IT technician proposes two different algorithmic strategies to remove the duplicate entries and compress the remaining items:
Algorithm A (Direct Search & Shift): Without sorting, iterate through the array using nested loops. Compare each element to every element that comes after it. If a duplicate is found, remove it by shifting all subsequent elements left by one position.
Algorithm B (Sort & Linear Scan): First, sort the array using an insertion sort. Once sorted, perform a single linear scan through the array, comparing each element only with its immediate neighbour. If they are equal, remove the duplicate by shifting all subsequent elements left by one position.
Evaluate both algorithms. In your answer, you should: - Compare the time complexity (best, average, and worst-case) of both algorithms, explaining the factors that influence their performance. - Compare the space complexity of both algorithms. - Discuss how the initial state of the array (such as being already sorted or having many duplicates) affects each algorithm. - Recommend, with justification, which algorithm is more suitable for a very large dataset of student IDs.
PastPaper.showAnswersPastPaper.hideAnswers
PastPaper.workedSolution
1. Time Complexity Analysis: - Algorithm A: - Always uses nested loops to compare every element with every other subsequent element. This results in a time complexity of \(O(N^2)\) for comparisons in the best, average, and worst cases. - Shifting elements takes \(O(N)\) per duplicate. If there are \(D\) duplicates, the shifting time complexity is \(O(D \times N)\). - Overall Time Complexity: Best, Average, and Worst-case are all \(O(N^2)\).
- Algorithm B: - Step 1 (Insertion Sort): Best-case (already sorted) is \(O(N)\) comparisons and no swaps. Average and worst-case (reversed) are \(O(N^2)\). - Step 2 (Linear Scan): Requires a single pass of \(O(N)\) comparisons. - Shifting elements also takes \(O(D \times N)\) where \(D\) is the number of duplicates. - Overall Time Complexity: Best-case is \(O(N)\) (when already sorted and no duplicates). Average and worst-case are \(O(N^2)\).
2. Space Complexity Analysis: - Both algorithms perform their sorting, searching, and shifting 'in-place' on the original array. - No additional arrays or data structures are created that scale with input size. - Therefore, both algorithms have an auxiliary space complexity of \(O(1)\) (constant space).
3. Impact of Initial States: - Already Sorted: Algorithm B performs exceptionally well, running in \(O(N)\) time. Algorithm A still executes its nested loop comparisons, taking \(O(N^2)\) time. - Highly Duplicated: Both algorithms will incur a high number of element shifts. However, Algorithm B will group duplicate elements together immediately during sorting, making them easier to identify in a single pass.
4. Recommendation: - For a very large dataset, Algorithm B is recommended over Algorithm A because it can exploit any pre-existing order in the dataset to run in linear time, whereas Algorithm A is hard-coded to perform quadratic comparisons. However, a candidate could correctly note that for extremely large unsorted datasets, an \(O(N \log N)\) sort (like Merge Sort) or using a hash-based set with \(O(N)\) average time complexity would be much better than either option.
PastPaper.markingScheme
Level 3 (7-9 marks): - Clear, accurate, and structured comparison of both algorithms' time complexities using Big O notation for best, average, and worst cases. - Correct identification of space complexity for both (O(1) / in-place). - Thorough discussion of how the initial state (sorted, reversed, duplicates) impacts each algorithm. - Logical, justified recommendation with technical reasoning.
Level 2 (4-6 marks): - Sound comparison of time complexities, though some Big O explanations or specific cases may be incomplete or have minor errors. - Mentions that both are in-place or have low space requirements, but may lack formal terminology. - Some discussion of the initial states or a recommendation is provided but lacks complete depth.
Level 1 (1-3 marks): - Basic comparison of the two approaches, showing a general understanding that sorting first might be useful or that nested loops are slow. - Identifies at least one correct aspect of space or time complexity. - Gives a recommendation with minimal or superficial technical justification.