Cambridge IAL · thinka-original Practice Paper

2026 Cambridge IAL Computer Science (9618) Practice Paper with Answers

Thinka Jun 2026 (V2) Cambridge International A Level-Style Mock — Computer Science (9618)

300 marks450 mins2026
An original Thinka practice paper modelled on the structure and difficulty of the Jun 2026 (V2) Cambridge International A Level Computer Science (9618) paper. Not affiliated with or reproduced from Cambridge.

Paper 1 Theory Fundamentals

Answer all questions. Calculators are not permitted.
15 Question · 42 marks
Question 1 · Multiple Choice
1.5 marks
A digital sound track is recorded with a sampling rate of \(44.1\text{ kHz}\), a sampling resolution of \(16\text{ bits}\), and \(2\) audio channels (stereo). Which expression correctly calculates the uncompressed file size of a \(3\text{-minute}\) recording in mebibytes (\(\text{MiB}\))?
  1. A.\(\dfrac{44\,100 \times 16 \times 2 \times 180}{8 \times 1024 \times 1024}\)
  2. B.\(\dfrac{44\,100 \times 16 \times 2 \times 3}{8 \times 1000 \times 1000}\)
  3. C.\(\dfrac{44.1 \times 16 \times 2 \times 180}{1024 \times 1024}\)
  4. D.\(\dfrac{44\,100 \times 16 \times 180}{8 \times 1024}\)
Show answer & marking scheme

Worked solution

To calculate uncompressed audio file size in mebibytes (\(\text{MiB}\)):
1. Convert duration to seconds: \(3\text{ minutes} = 3 \times 60 = 180\text{ seconds}\).
2. Calculate sampling rate in Hertz: \(44.1\text{ kHz} = 44\,100\text{ Hz}\) (samples per second).
3. Total bits \(= \text{sample rate} \times \text{bit depth} \times \text{channels} \times \text{duration in seconds} = 44\,100 \times 16 \times 2 \times 180\).
4. Convert bits to bytes by dividing by \(8\).
5. Convert bytes to mebibytes (\(\text{MiB}\)) using binary prefixes by dividing by \(1024 \times 1024\) (or \(2^{20}\)).

Thus, the expression is:
\[\frac{44\,100 \times 16 \times 2 \times 180}{8 \times 1024 \times 1024}\]

Marking scheme

1.5 marks for option A.
- 1 mark for correct identification of total bit calculation (\(44\,100 \times 16 \times 2 \times 180\)).
- 0.5 marks for correct binary prefix division (\(8 \times 1024 \times 1024\) for \(\text{MiB}\)).
Reject options using decimal powers of 10 (e.g. \(1000 \times 1000\)) as the question specifies \(\text{MiB}\) rather than \(\text{MB}\).
Question 2 · Multiple Choice
1.5 marks
Which sequence of Register Transfer Notation (RTN) statements correctly describes the fetch stage of the von Neumann Fetch-Execute cycle?
  1. A.\(\text{MDR} \leftarrow [\text{PC}]\); \(\text{MAR} \leftarrow [\text{MDR}]\); \(\text{PC} \leftarrow [\text{PC}] + 1\); \(\text{CIR} \leftarrow [\text{MAR}]\)
  2. B.\(\text{MAR} \leftarrow [\text{PC}]\); \(\text{PC} \leftarrow [\text{PC}] + 1\); \(\text{MDR} \leftarrow [[\text{MAR}]]\); \(\text{CIR} \leftarrow [\text{MDR}]\)
  3. C.\(\text{PC} \leftarrow [\text{MAR}]\); \(\text{MAR} \leftarrow [\text{MDR}]\); \(\text{MDR} \leftarrow [[\text{MAR}]]\); \(\text{CIR} \leftarrow [\text{PC}]\)
  4. D.\(\text{MAR} \leftarrow [\text{CIR}]\); \(\text{MDR} \leftarrow [[\text{MAR}]]\); \(\text{CIR} \leftarrow [\text{MDR}]\); \(\text{PC} \leftarrow [\text{PC}] + 1\)
Show answer & marking scheme

Worked solution

The fetch stage in the Fetch-Execute cycle follows these steps:
1. The address in the Program Counter (\(\text{PC}\)) is copied to the Memory Address Register (\(\text{MAR}\)): \(\text{MAR} \leftarrow [\text{PC}]\).
2. The \(\text{PC}\) is incremented by 1 to point to the next instruction: \(\text{PC} \leftarrow [\text{PC}] + 1\).
3. The instruction held in primary memory at the address stored in \(\text{MAR}\) is fetched into the Memory Data Register (\(\text{MDR}\)): \(\text{MDR} \leftarrow [[\text{MAR}]]\).
4. The instruction in the \(\text{MDR}\) is copied to the Current Instruction Register (\(\text{CIR}\)): \(\text{CIR} \leftarrow [\text{MDR}]\).

Marking scheme

1.5 marks for option B.
- Award full marks for the correct sequential transfer: \(\text{MAR} \leftarrow [\text{PC}]\), \(\text{PC} \leftarrow [\text{PC}] + 1\), \(\text{MDR} \leftarrow [[\text{MAR}]]\), \(\text{CIR} \leftarrow [\text{MDR}]\).
- Allow \(\text{PC} \leftarrow [\text{PC}] + 1\) occurring simultaneously with the memory read step.
Question 3 · Multiple Choice
1.5 marks
A database table \(\text{ModuleEnrolment}\) has the composite primary key \((\text{StudentID}, \text{ModuleCode})\) and contains the following non-key attributes:
- \(\text{StudentName}\) (depends only on \(\text{StudentID}\))
- \(\text{ModuleTitle}\) (depends only on \(\text{ModuleCode}\))
- \(\text{FinalMark}\) (depends on both \(\text{StudentID}\) and \(\text{ModuleCode}\))

Why is \(\text{ModuleEnrolment}\) in First Normal Form (1NF) but NOT in Second Normal Form (2NF)?
  1. A.It contains transitive dependencies between non-key attributes.
  2. B.It contains non-atomic attributes and repeating groups of data.
  3. C.It contains partial dependencies where non-key attributes depend on only part of the composite primary key.
  4. D.It lacks referential integrity constraints between foreign keys.
Show answer & marking scheme

Worked solution

A table is in First Normal Form (1NF) if it contains only atomic values and has a primary key. For a table to achieve Second Normal Form (2NF), it must already be in 1NF and contain no partial functional dependencies (i.e., no non-key attribute may be functionally dependent on only a part of a composite primary key).

In this table, \(\text{StudentName}\) depends solely on \(\text{StudentID}\) and \(\text{ModuleTitle}\) depends solely on \(\text{ModuleCode}\). These are partial key dependencies, violating the requirements for 2NF.

Marking scheme

1.5 marks for option C.
- 1.5 marks: Correctly identifying that non-key attributes exhibit partial functional dependency on components of the composite primary key.
- Reject option A (transitive dependencies are the criterion for 3NF, not 2NF).
- Reject option B (atomic attributes define 1NF conformance).
Question 4 · Multiple Choice
1.5 marks
An Ethernet local area network uses the Carrier Sense Multiple Access with Collision Detection (CSMA/CD) protocol. Which sequence of actions is executed immediately when a transmitting station detects a collision on the shared channel?
  1. A.The station immediately retransmits the frame at increased signal power to overwrite corrupted frames.
  2. B.The station sends an interrupt request to the network router to switch the topology to token ring.
  3. C.The station discards the frame permanently and logs an unrecoverable parity failure.
  4. D.The station transmits a jam signal, stops transmitting data, and waits for a random backoff time before attempting retransmission.
Show answer & marking scheme

Worked solution

Under the CSMA/CD protocol:
1. The node transmits data while continuing to listen to the channel.
2. When a collision occurs (detected by an abnormal signal voltage level), the transmitting node immediately halts data transmission and broadcasts a jam signal to ensure all other nodes on the network detect the collision.
3. The node then waits for a pseudo-random backoff period before attempting to sense the carrier again and retransmit the frame.

Marking scheme

1.5 marks for option D.
- Full marks for identifying: transmission of a jam signal, stopping data transmission, and applying a random backoff delay before retransmission.
- Reject answers suggesting immediate retransmission at higher power or switching transmission frequency.
Question 5 · Structured Technical Explanations
3.5 marks
A graphic designer is storing a simple black-and-white icon consisting of large uniform blocks of pixels.

(a) Describe how Run-Length Encoding (RLE) is used to compress this bitmap image data. [2]

(b) State one scenario where applying Run-Length Encoding to an image file would increase the overall file size rather than compress it, and explain why this occurs. [1.5]
Show answer & marking scheme

Worked solution

(a) Run-Length Encoding (RLE) scans the bitmap data and identifies consecutive identical pixel values (runs). Instead of storing each individual pixel repeatedly, it stores the pixel value (or colour code) together with a count of how many consecutive times that value occurs in sequence.

(b) When an image contains no or very few consecutive identical pixels (e.g., highly detailed, noisy, or dithered images with alternating colours), each run length is 1. Storing both the pixel value and the run count (e.g., '1, Red, 1, Blue...') requires more bytes than storing the raw pixel sequence alone, leading to an increase in total file size.

Marking scheme

(a) 1 mark per point to max 2:
- Identifies adjacent/consecutive identical pixel values / sequence of identical data elements [1]
- Replaces repeated data with a single value (colour/byte) and a frequency/count/run-length [1]

(b) 1.5 marks:
- Scenario: Image with high detail / noise / alternating adjacent pixels / no repeating pixel values [0.5]
- Explanation: Each pixel requires an additional byte/value to store the count (a run length of 1), adding overhead and thereby increasing total file size [1.0]
Question 6 · Structured Technical Explanations
3.5 marks
In a local area network using a bus topology, the Carrier Sense Multiple Access with Collision Detection (CSMA/CD) protocol is implemented.

(a) Explain why collision detection is necessary on this network architecture. [1.5]

(b) Describe the sequence of actions taken by a transmitting node when a collision is detected. [2]
Show answer & marking scheme

Worked solution

(a) A bus topology uses a shared transmission medium. If two or more devices check the carrier simultaneously, find it idle, and transmit frames at the same time, the signals interfere and corrupt each other (a collision). Collision detection is needed so nodes can identify corrupted data and recover.

(b) When a collision is detected:
1. The transmitting node immediately aborts the current frame transmission.
2. It broadcasts a high-frequency jam signal across the channel to ensure all other nodes detect the collision.
3. The node waits for a pseudo-random back-off time before re-sensing the channel and attempting retransmission.

Marking scheme

(a) 1.5 marks:
- Identifies shared medium / single transmission line [0.5]
- Explains that simultaneous transmissions result in signal overlap / data corruption / unreadable frames [1.0]

(b) 1 mark per point to max 2:
- Node stops/aborts frame transmission immediately [1]
- Node transmits a jam signal across the bus to notify all connected devices [1]
- Node waits for a random period of time (back-off algorithm) before listening to the line to retransmit [1]
Question 7 · Structured Technical Explanations
3.5 marks
During the execution of a user program, an I/O device generates a hardware interrupt.

(a) Describe how the Central Processing Unit (CPU) handles this interrupt up to the point where the Interrupt Service Routine (ISR) begins execution. [2]

(b) Explain why the contents of the Program Counter (PC) and Accumulator (ACC) must be pushed onto the stack before the ISR executes. [1.5]
Show answer & marking scheme

Worked solution

(a) At the end of the current Fetch-Execute cycle, the CPU checks for the presence of an interrupt signal. If an interrupt with higher priority is present, the contents of the Program Counter and other operational registers are saved onto the system stack. The CPU then loads the start address of the specific Interrupt Service Routine (obtained from an interrupt vector table) into the Program Counter.

(b) The ISR will overwrite the CPU registers (such as the Accumulator and Status Register) with its own working data while executing. Saving these values on the stack ensures that when the ISR completes, the original state and execution point of the interrupted program can be completely restored, allowing it to continue seamlessly without data loss.

Marking scheme

(a) 1 mark per point to max 2:
- CPU checks for interrupt flag/signal at the end of the current Fetch-Execute cycle [1]
- Current register values / CPU state are pushed / saved onto the system stack [1]
- PC is loaded with the start address of the ISR / vector address [1]

(b) 1.5 marks:
- Explains that the ISR uses the registers (ACC, status flags, etc.) during its own execution / will overwrite current values [0.5]
- Explains that saving them preserves the program context so it can resume exactly where it was interrupted without loss of computational state [1.0]
Question 8 · Structured Technical Explanations
3.5 marks
Software developers often link Dynamic Link Library (DLL) files rather than static libraries to their compiled applications.

(a) Describe what is meant by a Dynamic Link Library (DLL) file. [1.5]

(b) Explain two advantages of using dynamic linking over static linking for commercial desktop software. [2]
Show answer & marking scheme

Worked solution

(a) A Dynamic Link Library (DLL) is a collection of pre-compiled subroutines and resources that can be used by multiple programs simultaneously. The code is loaded into memory only when needed at runtime rather than being embedded into the executable binary during compilation.

(b) 1. Reduced storage and memory footprint: Because multiple executing programs can share a single copy of the DLL loaded in RAM, main memory and disk space requirements are significantly reduced.
2. Independent updates/maintenance: If a bug is fixed or an algorithm is upgraded in the DLL, the library file can be replaced without needing to recompile or redistribute the parent applications.

Marking scheme

(a) 1.5 marks:
- Pre-compiled collection of functions/code routines/resources [0.5]
- Linked/loaded into memory dynamically at run time (rather than compiled into the main executable) [1.0]

(b) 1 mark per valid advantage explained (max 2 marks):
- Smaller executable file size because library code is not embedded in every executable [1]
- Shared RAM usage because one instance of the library in memory can serve multiple running processes [1]
- Modular updates/patching: DLL can be updated/fixed independently without recompiling the main program [1]
Question 9 · Structured Technical Explanations
3.5 marks
A database system records transaction data and uses verification and validation checks.

(a) Distinguish between data validation and data verification in the context of data entry. [1.5]

(b) Explain how a parity block (two-dimensional parity check) can both detect and correct a single-bit transmission error. [2]
Show answer & marking scheme

Worked solution

(a) Data validation is an automated software check to ensure that entered data meets specific predefined criteria (such as range, length, or format) and is sensible/reasonable. Data verification is a process designed to ensure that the data entered matches the original source document exactly (e.g., via double entry or visual comparison).

(b) In a parity block, a parity bit is added to each individual byte (horizontal parity), and an additional parity byte is generated across the entire block of bytes (vertical parity). If a single bit flips during transmission, it creates a parity mismatch in one specific horizontal row and one specific vertical column. The intersection of this row and column precisely identifies the corrupted bit, allowing the receiver to invert it to correct the error.

Marking scheme

(a) 1.5 marks:
- Validation: Automated check that data follows rules / is sensible / reasonable / acceptable format [0.5]
- Verification: Checking that data matches the original source / is copied accurately [0.5]
- Distinct contrast established (e.g., valid data can still be incorrect/inaccurate) [0.5]

(b) 1 mark per point to max 2:
- Employs horizontal parity (for each byte/row) and vertical parity (for each column/block) [1]
- An error causes a parity violation in one row and one column [1]
- The intersection of the invalid row and column pinpoints the exact bit location, which is inverted/corrected [1]
Question 10 · Structured Technical Explanations
3.5 marks
A logistics firm is migrating its fleet records from flat files to a normalised relational database.

(a) Explain what is meant by referential integrity in a relational database. [1.5]

(b) Describe how a table in First Normal Form (1NF) with a composite primary key is transformed into Second Normal Form (2NF). [2]
Show answer & marking scheme

Worked solution

(a) Referential integrity is a database constraint that ensures relationships between tables remain consistent. It guarantees that any foreign key value stored in a child table must correspond to a valid, existing primary key value in the referenced parent table, preventing orphaned records.

(b) To convert a table from 1NF to 2NF:
1. Identify any partial functional dependencies, where non-key attributes depend on only a part of the composite primary key rather than the entire key.
2. Remove these partially dependent attributes from the original table.
3. Create new tables containing the partial key and the non-key attributes that depend on it, assigning that partial key as the primary key of the new table.

Marking scheme

(a) 1.5 marks:
- Definition: Ensures consistency/validity of relationships between linked tables [0.5]
- Rule: Foreign key values must match an existing primary key value in the related table (or be null) / prevents orphaned records [1.0]

(b) 1 mark per point to max 2:
- Identifies/removes partial dependencies (attributes dependent on part of a composite primary key) [1]
- Places the partially dependent attributes into a new/separate table [1]
- The partial primary key attribute becomes the primary key of the new table [1]
Question 11 · structured
4 marks
A database stores information about equipment maintenance in a research laboratory. The database contains a table named EQUIPMENT, which has EquipmentID as its primary key.

A new table, INSPECTION, needs to be created to store records of each routine check.

The attributes and types required for INSPECTION are:
- InspectionID: whole number, primary key
- EquipmentID: fixed-length text of 6 characters, foreign key referencing EQUIPMENT
- InspectionDate: date of the inspection
- Passed: whether the equipment passed the inspection or not (true/false)
- FeeCharged: numeric value with fractional parts

Write an SQL script to define and create the table INSPECTION with all appropriate constraints and field types. [4]
Show answer & marking scheme

Worked solution

The SQL DDL statement requires creating the table with all specified fields, suitable data types, primary key definition, and foreign key constraint referencing the parent table.

```sql
CREATE TABLE INSPECTION (
InspectionID INTEGER,
EquipmentID VARCHAR(6),
InspectionDate DATE,
Passed BOOLEAN,
FeeCharged REAL,
PRIMARY KEY (InspectionID),
FOREIGN KEY (EquipmentID) REFERENCES EQUIPMENT(EquipmentID)
);
```

Marking scheme

1 mark per marking point (max 4):
- MP1: Correct `CREATE TABLE INSPECTION (...)` clause.
- MP2: Correct field definitions and types for `InspectionDate DATE`, `Passed BOOLEAN`, and `FeeCharged REAL` (accept `NUMERIC` / `DECIMAL` / `FLOAT`).
- MP3: Correct primary key specification `PRIMARY KEY (InspectionID)` (or inline `InspectionID INTEGER PRIMARY KEY`).
- MP4: Correct foreign key specification with datatype `FOREIGN KEY (EquipmentID) REFERENCES EQUIPMENT(EquipmentID)` (allow `CHARACTER(6)` or `CHAR(6)` or `VARCHAR(6)`).
Question 12 · structured
4 marks
A veterinary clinic manages its data using a relational database with two tables:

PATIENT(PatientID, PatientName, Species, MicrochipNo, OwnerID)
APPOINTMENT(AppointmentID, PatientID, AppDate, Fee)

Write an SQL query to display the PatientName, AppDate, and Fee for all appointments where:
- The Species is 'Feline'
- The Fee is strictly greater than 45.00

The results must be sorted in descending order of AppDate. [4]
Show answer & marking scheme

Worked solution

To extract data across two tables, an `INNER JOIN` (or equi-join in the `WHERE` clause) must be used on the shared key `PatientID`.

```sql
SELECT PATIENT.PatientName, APPOINTMENT.AppDate, APPOINTMENT.Fee
FROM PATIENT
INNER JOIN APPOINTMENT ON PATIENT.PatientID = APPOINTMENT.PatientID
WHERE PATIENT.Species = 'Feline' AND APPOINTMENT.Fee > 45.00
ORDER BY APPOINTMENT.AppDate DESC;
```

Marking scheme

1 mark per marking point (max 4):
- MP1: Correct `SELECT` clause listing `PatientName`, `AppDate`, `Fee` (table qualifiers optional where unique).
- MP2: Correct join syntax (`FROM PATIENT INNER JOIN APPOINTMENT ON PATIENT.PatientID = APPOINTMENT.PatientID` or `FROM PATIENT, APPOINTMENT WHERE PATIENT.PatientID = APPOINTMENT.PatientID`).
- MP3: Correct condition `WHERE Species = 'Feline' AND Fee > 45.00` (or linked with join condition if comma join used).
- MP4: Correct ordering `ORDER BY AppDate DESC`.
Question 13 · structured
4 marks
A public library uses a database table defined as follows:

BOOK_LOAN(LoanID, MemberID, ISBN, ReturnDate, OverdueFine)

(a) Write an SQL statement to update the OverdueFine to 6.50 for all records where ReturnDate is before 2026-01-15 and the current OverdueFine is equal to 0.00. [2]

(b) Write an SQL statement to add a new column named LoanStatus of type VARCHAR(20) to the table BOOK_LOAN. [2]
Show answer & marking scheme

Worked solution

(a) An `UPDATE` query modifies existing records matching the specific criteria:
```sql
UPDATE BOOK_LOAN
SET OverdueFine = 6.50
WHERE ReturnDate < '2026-01-15' AND OverdueFine = 0.00;
```

(b) An `ALTER TABLE` query with an `ADD` clause is used to modify the table structure:
```sql
ALTER TABLE BOOK_LOAN
ADD LoanStatus VARCHAR(20);
```

Marking scheme

(a) 2 marks:
- MP1: `UPDATE BOOK_LOAN SET OverdueFine = 6.50`
- MP2: `WHERE ReturnDate < '2026-01-15' AND OverdueFine = 0.00` (allow `= 0`)

(b) 2 marks:
- MP3: `ALTER TABLE BOOK_LOAN`
- MP4: `ADD LoanStatus VARCHAR(20);` (allow `ADD COLUMN LoanStatus VARCHAR(20);`)
Question 14 · short-answer
1.5 marks
A logic circuit has three inputs \( A \), \( B \), and \( C \).

The output \( X \) is represented by the Boolean expression:

\[ X = (A \text{ NAND } B) \text{ AND } (B \text{ XOR } C) \]

Complete the truth table by stating the values of \( X \) for each row from top to bottom.

$$\begin{array}{|c|c|c|c|}
\hline
A & B & C & X \\
\hline
0 & 0 & 0 & \text{---} \\
0 & 0 & 1 & \text{---} \\
0 & 1 & 0 & \text{---} \\
0 & 1 & 1 & \text{---} \\
1 & 0 & 0 & \text{---} \\
1 & 0 & 1 & \text{---} \\
1 & 1 & 0 & \text{---} \\
1 & 1 & 1 & \text{---} \\
\hline
\end{array}$$
Show answer & marking scheme

Worked solution

To evaluate \( X = (A \text{ NAND } B) \text{ AND } (B \text{ XOR } C) \):

1. Evaluate \( A \text{ NAND } B \):
- Output is 0 only when \( A = 1 \) and \( B = 1 \) (rows 7 and 8); otherwise 1.

2. Evaluate \( B \text{ XOR } C \):
- Output is 1 when \( B \) and \( C \) are different (rows 2, 3, 6, 7); otherwise 0.

3. Evaluate \( X = (A \text{ NAND } B) \text{ AND } (B \text{ XOR } C) \):
- Row 1 (0, 0, 0): \( 1 \text{ AND } 0 = 0 \)
- Row 2 (0, 0, 1): \( 1 \text{ AND } 1 = 1 \)
- Row 3 (0, 1, 0): \( 1 \text{ AND } 1 = 1 \)
- Row 4 (0, 1, 1): \( 1 \text{ AND } 0 = 0 \)
- Row 5 (1, 0, 0): \( 1 \text{ AND } 0 = 0 \)
- Row 6 (1, 0, 1): \( 1 \text{ AND } 1 = 1 \)
- Row 7 (1, 1, 0): \( 0 \text{ AND } 1 = 0 \)
- Row 8 (1, 1, 1): \( 0 \text{ AND } 0 = 0 \)

Marking scheme

1.5 marks total:
- 1.5 marks for all 8 output values correct: 0, 1, 1, 0, 0, 1, 0, 0
- 1.0 mark if 6 or 7 output values are correct
- 0.5 marks if 4 or 5 output values are correct
Question 15 · short-answer
1.5 marks
An automated greenhouse system controls a water pump (\( P \)). The pump is switched on (\( P = 1 \)) based on the inputs from three binary sensors:

- \( M = 1 \) if soil moisture is low (dry), \( M = 0 \) if moisture is adequate
- \( T = 1 \) if ambient temperature is high, \( T = 0 \) if temperature is normal
- \( R = 1 \) if the water reservoir level is sufficient, \( R = 0 \) if water level is low

The water pump is activated (\( P = 1 \)) only when the reservoir level is sufficient (\( R = 1 \)) AND either of the following conditions is met:
- The soil moisture is low (\( M = 1 \)), OR
- The ambient temperature is high (\( T = 1 \)) and the soil moisture is adequate (\( M = 0 \)).

Write a logic expression for \( P \) using the inputs \( M \), \( T \), \( R \) and the logic operators AND, OR, and NOT.
Show answer & marking scheme

Worked solution

Let the conditions be structured step-by-step:
1. Reservoir level is sufficient: \( R \)
2. Condition 1: Soil moisture is low: \( M \)
3. Condition 2: Ambient temperature is high and moisture is adequate: \( T \text{ AND NOT } M \)
4. Either condition met: \( M \text{ OR } (T \text{ AND NOT } M) \)
5. Combined with reservoir check: \( P = R \text{ AND } (M \text{ OR } (T \text{ AND NOT } M)) \)

Note: Equivalent simplified expressions such as \( P = R \text{ AND } (M \text{ OR } T) \) or \( P = (R \text{ AND } M) \text{ OR } (R \text{ AND } T \text{ AND NOT } M) \) are also logically correct.

Marking scheme

1.5 marks total:
- 1.5 marks for fully correct logic expression: \( P = R \text{ AND } (M \text{ OR } (T \text{ AND NOT } M)) \) or valid equivalent like \( P = R \text{ AND } (M \text{ OR } T) \)
- 1.0 mark for correctly identifying the sub-expression \( (M \text{ OR } (T \text{ AND NOT } M)) \) but omitting or misplacing \( R \text{ AND } \)
- 0.5 marks for correctly writing \( (T \text{ AND NOT } M) \) as a sub-clause

Ready to test yourself?

Turn these notes into exam-style practice. Get unlimited AI questions on this topic with instant marking and explanations.

Practice This Topic

Paper 2 Fundamental Problem-solving and Programming Skills

Answer all questions. Refer to the insert for pseudocode functions and operators.
11 Question · 50.010000000000005 marks
Question 1 · Pseudocode Algorithm Completion
5 marks
A weather monitoring system stores hourly temperature readings in a text file named `TempLog.txt`. Each line of the file contains a single temperature reading stored as a string representation of a real number.

A procedure `ProcessTemperatures` is designed to:
- open the file `TempLog.txt` for reading
- read every temperature from the file until the end of the file is reached
- convert each reading to a real number
- count how many readings fall strictly below `0.0` degrees Celsius
- calculate the average (mean) of all temperatures in the file
- output the total count of sub-zero temperatures and the calculated average temperature
- close the file.

Complete the pseudocode for the procedure `ProcessTemperatures` by filling in the missing code for spaces `[1]` to `[5]`.

```text
PROCEDURE ProcessTemperatures()
DECLARE LineData : STRING
DECLARE Temperature, TotalTemp, AverageTemp : REAL
DECLARE CountTotal, CountSubZero : INTEGER

CountTotal <- 0
CountSubZero <- 0
TotalTemp <- 0.0

OPENFILE "TempLog.txt" FOR READ

WHILE [ 1 ] DO
READFILE "TempLog.txt", LineData
Temperature <- STRING_TO_REAL(LineData)
CountTotal <- CountTotal + 1
TotalTemp <- TotalTemp + Temperature

IF [ 2 ] THEN
CountSubZero <- CountSubZero + 1
ENDIF
ENDWHILE

[ 3 ]

IF CountTotal > 0 THEN
AverageTemp <- [ 4 ]
OUTPUT "Sub-zero count: ", CountSubZero
OUTPUT "Average temperature: ", AverageTemp
ELSE
OUTPUT "No data recorded."
ENDIF
ENDPROCEDURE
```

State the missing pseudocode for each of the following:

`[1]` .........................................................................................................................

`[2]` .........................................................................................................................

`[3]` .........................................................................................................................

`[4]` .........................................................................................................................

`[5]` Write the single line of pseudocode required immediately before `ENDPROCEDURE` that is currently missing from the module:

`[5]` .........................................................................................................................
Show answer & marking scheme

Worked solution

1. `NOT EOF("TempLog.txt")` ensures the file loop continues reading until the end of the file is encountered.
2. `Temperature < 0.0` checks if the reading is strictly below zero.
3. `CLOSEFILE "TempLog.txt"` closes the opened file resource (can be placed here or at `[5]`).
4. `TotalTemp / CountTotal` computes the arithmetic mean.
5. If the file was not closed at `[3]`, `CLOSEFILE "TempLog.txt"` must be called before the procedure finishes.

Marking scheme

1 mark for each correct answer:

1. `NOT EOF("TempLog.txt")`
- Accept: `NOT EOF("TempLog.txt") = TRUE`
- Do not accept: `EOF("TempLog.txt")` without `NOT`

2. `Temperature < 0.0` or `Temperature < 0`
- Do not accept: `<=` (must be strictly below 0.0)

3. `CLOSEFILE "TempLog.txt"` or `CLOSEFILE("TempLog.txt")`
- Allow if candidate places file close statement here or in space [5]

4. `TotalTemp / CountTotal`
- Do not accept: `DIV` (division of real values must use `/`)

5. `CLOSEFILE "TempLog.txt"` (if not already awarded for [3]; allow valid cleanup / alternative equivalent if file was closed at [3])
Question 2 · Pseudocode Algorithm Completion
5 marks
A function `CountVowelRuns` takes a string parameter `InputString` and counts the number of separate 'vowel runs' contained within it. A vowel run is defined as a contiguous sequence of one or more vowel characters (`'A'`, `'E'`, `'I'`, `'O'`, `'U'`, case-insensitive).

For example:
- `CountVowelRuns("BEAUTIFUL")` returns `3` (the runs are `"EAU"`, `"I"`, and `"U"`)
- `CountVowelRuns("STREAM")` returns `1` (the run is `"EA"`)
- `CountVowelRuns("RHYTHM")` returns `0`

The following built-in string functions are available:
- `LENGTH(Str : STRING) RETURNS INTEGER` : returns the number of characters in `Str`
- `MID(Str : STRING, Start : INTEGER, Length : INTEGER) RETURNS STRING` : returns a substring starting at position `Start` of length `Length`
- `UCASE(Str : STRING) RETURNS STRING` or `UCASE(Ch : CHAR) RETURNS CHAR` : returns the upper-case equivalent

Complete the pseudocode algorithm by providing the missing statements for `[1]` to `[5]`.

```text
FUNCTION CountVowelRuns(InputString : STRING) RETURNS INTEGER
DECLARE RunCount, Index : INTEGER
DECLARE InRun : BOOLEAN
DECLARE NextChar : CHAR

RunCount <- 0
InRun <- FALSE

FOR Index <- 1 TO [ 1 ]
NextChar <- UCASE(MID(InputString, Index, 1))

IF NextChar = 'A' OR NextChar = 'E' OR NextChar = 'I' OR NextChar = 'O' OR NextChar = 'U' THEN
IF [ 2 ] THEN
RunCount <- RunCount + 1
InRun <- [ 3 ]
ENDIF
ELSE
[ 4 ]
ENDIF
NEXT Index

[ 5 ]
ENDFUNCTION
```

State the missing pseudocode for each of the following:

`[1]` .........................................................................................................................

`[2]` .........................................................................................................................

`[3]` .........................................................................................................................

`[4]` .........................................................................................................................

`[5]` .........................................................................................................................
Show answer & marking scheme

Worked solution

1. `LENGTH(InputString)` sets the upper limit of the loop across every character in the string.
2. `InRun = FALSE` (or `NOT InRun`) checks if the current vowel is the start of a new vowel sequence.
3. `InRun <- TRUE` updates the flag to signify that we are currently inside a vowel run.
4. `InRun <- FALSE` resets the flag when a non-vowel character is encountered.
5. `RETURN RunCount` returns the final integer tally of vowel runs from the function.

Marking scheme

1 mark for each correct line:

1. `LENGTH(InputString)`
- Accept: `LENGTH(InputString)`

2. `NOT InRun` or `InRun = FALSE`
- Accept: `InRun = False`

3. `TRUE` or `InRun <- TRUE`
- Accept: `True`

4. `InRun <- FALSE`
- Accept: `InRun = FALSE` (allow assignment syntax variations like `:=`)

5. `RETURN RunCount`
- Do not accept: `OUTPUT RunCount` (must be RETURN in a FUNCTION)
Question 3 · Pseudocode Algorithm Completion
5 marks
A 2D array `StudentMarks` stores test marks for 40 students across 5 assessment modules:

`DECLARE StudentMarks : ARRAY[1:40, 1:5] OF INTEGER`

A procedure `AnalysePerformance` is required to:
1. Find and output the student identifier (represented by the row index `1` to `40`) who achieved the highest total score across all 5 modules. If more than one student shares the highest total, output the first one found.
2. Count and output how many students passed all 5 modules (a student passes a module if their score is greater than or equal to `50`).

Complete the pseudocode for the procedure `AnalysePerformance` by filling in the missing code for spaces `[1]` to `[5]`.

```text
PROCEDURE AnalysePerformance()
DECLARE Student, Module, HighestStudent, AllPassCount, CurrentTotal : INTEGER
DECLARE MaxTotal : INTEGER
DECLARE PassedAll : BOOLEAN

MaxTotal <- -1
HighestStudent <- 0
AllPassCount <- 0

FOR Student <- 1 TO 40
CurrentTotal <- 0
PassedAll <- TRUE

FOR Module <- 1 TO 5
CurrentTotal <- CurrentTotal + [ 1 ]

IF StudentMarks[Student, Module] < 50 THEN
[ 2 ]
ENDIF
NEXT Module

IF [ 3 ] THEN
MaxTotal <- CurrentTotal
HighestStudent <- Student
ENDIF

IF [ 4 ] THEN
AllPassCount <- AllPassCount + 1
ENDIF
NEXT Student

OUTPUT "Top Student Index: ", HighestStudent
OUTPUT "Total students passing all modules: ", [ 5 ]
ENDPROCEDURE
```

State the missing pseudocode for each of the following:

`[1]` .........................................................................................................................

`[2]` .........................................................................................................................

`[3]` .........................................................................................................................

`[4]` .........................................................................................................................

`[5]` .........................................................................................................................
Show answer & marking scheme

Worked solution

1. `StudentMarks[Student, Module]` retrieves the mark for the current student and module to accumulate into `CurrentTotal`.
2. `PassedAll <- FALSE` flags that the student failed at least one module when a mark below 50 is detected.
3. `CurrentTotal > MaxTotal` tests if the student's total mark is strictly greater than the highest total recorded so far.
4. `PassedAll = TRUE` (or `PassedAll`) checks if the student maintained a pass mark across all 5 modules.
5. `AllPassCount` outputs the total count of students who passed every module.

Marking scheme

1 mark for each correct line:

1. `StudentMarks[Student, Module]`
- Accept: `StudentMarks[Student][Module]`

2. `PassedAll <- FALSE`
- Accept: `PassedAll = FALSE` / `PassedAll := FALSE`

3. `CurrentTotal > MaxTotal`
- Do not accept: `>=` (the requirement specifies outputting the first one found if totals are tied)

4. `PassedAll` or `PassedAll = TRUE`
- Accept: `PassedAll == TRUE`

5. `AllPassCount`
Question 4 · free-response
2.67 marks
A software developer is designing a module for a flight booking system. The module accepts an integer input representing the number of passenger bags to check in, named \( \text{BaggageCount} \).

The validation rule specifies that \( \text{BaggageCount} \) must be an integer from 0 to 5 inclusive.

Complete the test plan below by identifying one appropriate test value for each specified test data category, along with the expected result of the validation check:

(a) Normal test data [1]
(b) Extreme / Boundary test data that is valid [1]
(c) Abnormal test data [1]
Show answer & marking scheme

Worked solution

(a) Normal test data lies comfortably within the acceptable range (0 to 5 inclusive). Acceptable values include 1, 2, 3, or 4. The expected outcome is that the data is accepted as valid.
(b) Boundary / Extreme test data lies on the exact limits of the acceptable range. For valid boundary test data, the allowed values are either the lower limit (0) or the upper limit (5). Expected outcome is that the data is accepted as valid.
(c) Abnormal test data is data that is outside the permitted range or of an invalid data type (e.g., negative integer such as -1, integer above range such as 6 or 10, or a non-numeric string such as "three"). The expected outcome is that the system rejects the input and displays an error.

Marking scheme

1 mark per test data category with matching expected result:

(a) Normal:
- 1 mark for any integer in the range 1 to 4 inclusive AND expected result: Accepted / Valid.

(b) Extreme / Boundary (Valid):
- 1 mark for 0 OR 5 AND expected result: Accepted / Valid.

(c) Abnormal:
- 1 mark for any integer < 0 OR > 5 OR non-integer / string value (e.g., -1, 6, 7, 3.5, "two") AND expected result: Rejected / Error flagged / Not accepted.
Question 5 · free-response
2.67 marks
An automated barrier gate at an underground car park operates using a finite-state machine with four possible states:
- `CLOSED` (the barrier is down across the lane)
- `OPENING` (the motor is actively raising the barrier)
- `OPEN` (the barrier is fully raised)
- `CLOSING` (the motor is actively lowering the barrier)

The barrier system responds to the following events:
- `TicketValidated`: triggered when a driver scans a valid ticket while the barrier is `CLOSED`.
- `UpperLimitReached`: triggered by a sensor when the barrier reaches the maximum vertical position.
- `VehicleCleared`: triggered by a ground induction loop when the car leaves the exit zone.
- `LowerLimitReached`: triggered by a sensor when the barrier reaches the fully horizontal position.

Complete the state-transition table by stating the Next State for each row:

| Current State | Event | Next State |
| :--- | :--- | :--- |
| `CLOSED` | `TicketValidated` | (i) ........................................ |
| `OPENING` | `UpperLimitReached` | (ii) ........................................ |
| `OPEN` | `VehicleCleared` | (iii) ........................................ |
| `CLOSING` | `LowerLimitReached` | (iv) ........................................ |
Show answer & marking scheme

Worked solution

(i) When the barrier is in state `CLOSED` and the `TicketValidated` event occurs, the motor begins raising the barrier, transitioning to `OPENING`.
(ii) While `OPENING`, once the `UpperLimitReached` sensor triggers, the motor stops and the barrier is stationary in the fully raised position, transitioning to `OPEN`.
(iii) While `OPEN`, after the car drives through and triggers `VehicleCleared`, the motor begins lowering the barrier, transitioning to `CLOSING`.
(iv) While `CLOSING`, once the `LowerLimitReached` sensor detects that the arm has reached the ground horizontal position, the barrier transitions back to `CLOSED`.

Marking scheme

Mark breakdown:
- 1 mark for (i) `OPENING` and (ii) `OPEN` both correct.
- 1 mark for (iii) `CLOSING`.
- 1 mark for (iv) `CLOSED`.
(Allow full marks if all 4 correct; award 2 marks if 3 are correct; award 1 mark if 2 are correct).
Question 6 · free-response
2.67 marks
A digital security safe keypad module transitions between three states:
- `LOCKED`
- `UNLOCKED`
- `DISABLED`

The variable `AttemptCount` stores the number of consecutive incorrect passcode attempts. When `AttemptCount` reaches 3, the safe transitions from `LOCKED` to `DISABLED`.

(a) State the difference between black-box testing and white-box testing when evaluating this keypad module. [2]

(b) State the type of maintenance required if the keypad software is modified to allow 5 failed passcode attempts instead of 3 due to updated client requirements. [1]
Show answer & marking scheme

Worked solution

(a) Black-box testing evaluates the functionality of the program against the requirements specification by supplying inputs and observing outputs, without any knowledge or reference to the internal program code or algorithmic structure.
White-box testing examines the internal structure, pathways, and logic of the program code, testing all possible execution paths and conditions (such as tracing the `AttemptCount` variable directly).

(b) Perfective maintenance involves modifying a software system to enhance performance, improve functionality, or adapt to new/changed user requirements when the software is already functioning without error.

Marking scheme

(a) 1 mark for black-box description:
- Tests input/output behaviour against requirements / without viewing or knowing internal code structure.
1 mark for white-box description:
- Tests internal code logic / statements / pathways with full visibility of source code.

(b) 1 mark for:
- Perfective (maintenance)
[Do not accept Adaptive or Corrective]
Question 7 · Stack Trace & ADT Simulation
4.5 marks
A stack abstract data type (ADT) is implemented using a 1D array, TokenStack, with index values from 1 to 6. A pointer variable, TopPointer, stores the index of the top element of the stack. When the stack is empty, TopPointer contains 0.

The following algorithm evaluates an array of instructions using the stack:
DECLARE OpCode : ARRAY[1:8] OF STRING
OpCode <- ["PUSH 14", "PUSH 6", "ADD", "PUSH 4", "SUB", "PUSH 9", "SWAP", "POP"]
The operations behave as follows:
  • PUSH n: Increments TopPointer by 1 and inserts the integer n.
  • POP: Removes and discards the element at TopPointer, decrementing TopPointer by 1.
  • ADD: Pops the top two numbers, adds them together, and pushes the result back onto the stack.
  • SUB: Pops the top number (), pops the next number (a), subtracts b from a (a - b), and pushes the result back onto the stack.
  • SWAP: Swaps the positions of the top two elements on the stack without changing TopPointer.

Complete the trace table showing the contents of TopPointer and TokenStack[1:6] after each of the 8 instructions is executed.
Show answer & marking scheme

Worked solution

Step-by-step trace of each instruction:

Initial State: TopPointer = 0, TokenStack = [empty, empty, empty, empty, empty, empty]
1. PUSH 14: TopPointer becomes 1. TokenStack[1] = 14.
2. PUSH 6: TopPointer becomes 2. TokenStack[2] = 6.
3. ADD: Pops 6 (TopPointer=1), pops 14 (TopPointer=0), adds 14 + 6 = 20. Pushes 20. TopPointer becomes 1. TokenStack[1] = 20.
4. PUSH 4: TopPointer becomes 2. TokenStack[2] = 4.
5. SUB: Pops 4 (b=4, TopPointer=1), pops 20 (a=20, TopPointer=0), calculates a - b = 20 - 4 = 16. Pushes 16. TopPointer becomes 1. TokenStack[1] = 16.
6. PUSH 9: TopPointer becomes 2. TokenStack[2] = 9.
7. SWAP: Swaps TokenStack[2] (9) and TokenStack[1] (16). TokenStack[1] = 9, TokenStack[2] = 16. TopPointer remains 2.
8. POP: Removes TokenStack[2]. TopPointer becomes 1. TokenStack[1] = 9.

Summary of trace table states (TopPointer, Stack contents [1], [2]):
- After Inst 1: TopPointer = 1, [14]
- After Inst 2: TopPointer = 2, [14, 6]
- After Inst 3: TopPointer = 1, [20]
- After Inst 4: TopPointer = 2, [20, 4]
- After Inst 5: TopPointer = 1, [16]
- After Inst 6: TopPointer = 2, [16, 9]
- After Inst 7: TopPointer = 2, [9, 16]
- After Inst 8: TopPointer = 1, [9]

Marking scheme

1 mark: Correct values of TopPointer and TokenStack after Instructions 1, 2, and 3 (TopPointer = 1, Stack[1] = 20).
1 mark: Correct values of TopPointer and TokenStack after Instructions 4 and 5 (TopPointer = 1, Stack[1] = 16).
1 mark: Correct values of TopPointer and TokenStack after Instructions 6 and 7 (TopPointer = 2, Stack[1] = 9, Stack[2] = 16).
1 mark: Correct final values after Instruction 8 (TopPointer = 1, Stack[1] = 9).
0.5 marks: Maintaining correct TopPointer updates throughout the entire trace.
Question 8 · Stack Trace & ADT Simulation
4.5 marks
A circular queue ADT named PrintBuffer is implemented using a 1D array of size 5 with indices 1 TO 5. Two integer pointers, HeadPointer and TailPointer, and a counter, QueueLength, track the queue status.

The initial configuration is:
HeadPointer <- 1
TailPointer <- 0
QueueLength <- 0
PrintBuffer <- ["", "", "", "", ""]

The procedure Enqueue(DocID : STRING) executes the following logic:
IF QueueLength = 5 THEN
OUTPUT "Buffer Full"
ELSE
TailPointer <- (TailPointer MOD 5) + 1
PrintBuffer[TailPointer] <- DocID
QueueLength <- QueueLength + 1
ENDIF
The procedure Dequeue() executes the following logic:
IF QueueLength = 0 THEN
OUTPUT "Buffer Empty"
ELSE
PrintBuffer[HeadPointer] <- ""
HeadPointer <- (HeadPointer MOD 5) + 1
QueueLength <- QueueLength - 1
ENDIF
Simulate the state of the queue after the following sequence of calls is executed in order:
1. Enqueue("DOC_A")
2. Enqueue("DOC_B")
3. Enqueue("DOC_C")
4. Dequeue()
5. Enqueue("DOC_D")
6. Enqueue("DOC_E")
7. Enqueue("DOC_F")
8. Dequeue()

State the final values of HeadPointer, TailPointer, QueueLength, and the complete contents of PrintBuffer[1:5].
Show answer & marking scheme

Worked solution

Detailed step-by-step trace:

Initial: Head=1, Tail=0, Length=0, Array=["", "", "", "", ""]

1. Enqueue("DOC_A"):
- TailPointer = (0 MOD 5) + 1 = 1
- PrintBuffer[1] = "DOC_A"
- QueueLength = 1

2. Enqueue("DOC_B"):
- TailPointer = (1 MOD 5) + 1 = 2
- PrintBuffer[2] = "DOC_B"
- QueueLength = 2

3. Enqueue("DOC_C"):
- TailPointer = (2 MOD 5) + 1 = 3
- PrintBuffer[3] = "DOC_C"
- QueueLength = 3

4. Dequeue():
- PrintBuffer[1] = ""
- HeadPointer = (1 MOD 5) + 1 = 2
- QueueLength = 2

5. Enqueue("DOC_D"):
- TailPointer = (3 MOD 5) + 1 = 4
- PrintBuffer[4] = "DOC_D"
- QueueLength = 3

6. Enqueue("DOC_E"):
- TailPointer = (4 MOD 5) + 1 = 5
- PrintBuffer[5] = "DOC_E"
- QueueLength = 4

7. Enqueue("DOC_F"):
- TailPointer = (5 MOD 5) + 1 = 1
- PrintBuffer[1] = "DOC_F"
- QueueLength = 5

8. Dequeue():
- PrintBuffer[2] = ""
- HeadPointer = (2 MOD 5) + 1 = 3
- QueueLength = 4

Final values:
- HeadPointer: 3
- TailPointer: 1
- QueueLength: 4
- PrintBuffer: ["DOC_F", "", "DOC_C", "DOC_D", "DOC_E"]

Marking scheme

1 mark: Correct value of HeadPointer (3).
1 mark: Correct value of TailPointer (1).
1 mark: Correct value of QueueLength (4).
1 mark: Correct array contents for PrintBuffer ["DOC_F", "", "DOC_C", "DOC_D", "DOC_E"].
0.5 marks: Correctly demonstrating the wrap-around arithmetic for TailPointer at step 7.
Question 9 · Algorithm Optimization & Procedural Pseudocode
6 marks
An environmental telemetry unit stores daily air quality readings in a 1D array, `AirQualityIndex`, with index bounds `1` to `TotalDays` (where `TotalDays >= 2`).

A programmer wants to sort the array into ascending order using an optimized bubble sort algorithm.

The algorithm must:
- stop iterating immediately if a complete pass occurs with no swaps made
- reduce the number of adjacent comparisons on each successive pass so that already sorted trailing elements are not re-checked

Write pseudocode for the procedure `OptimisedSort(AirQualityIndex, TotalDays)`.

```text
// AirQualityIndex : ARRAY[1:TotalDays] OF INTEGER
// TotalDays : INTEGER
```
[6]
Show answer & marking scheme

Worked solution

To optimize the bubble sort algorithm:
1. Use a boolean flag (`Swapped`) initialized to `FALSE` before each pass. If any swap takes place during a pass, set `Swapped` to `TRUE`.
2. Maintain an outer loop (`REPEAT...UNTIL` or `WHILE`) that terminates when `Swapped` remains `FALSE` after a pass (or when all passes are exhausted).
3. Maintain a comparison bound (`Limit`) initially set to `TotalDays - 1`, and decrement `Limit` by 1 after each complete inner pass, ensuring that the largest elements bubbling to the end are not re-evaluated in subsequent passes.

Marking scheme

1 mark per point (max 6 marks):
- MP1: Correct procedure header and parameter declaration (with array passed `BYREF` or parameter list with types).
- MP2: Correct initialization of outer loop condition/flag (`Swapped <- FALSE`) inside outer loop and initial inner limit (`Limit <- TotalDays - 1`).
- MP3: Inner `FOR` loop running from index `1` to `Limit` (or `TotalDays - 1` decremented).
- MP4: Correct adjacent element comparison (`AirQualityIndex[Index] > AirQualityIndex[Index + 1]`).
- MP5: Correct swap logic using a temporary variable `Temp` AND setting `Swapped <- TRUE`.
- MP6: Decrementing `Limit` after inner loop AND outer loop termination condition on `Swapped = FALSE` (or `NOT Swapped`).

Guidance: Accept equivalent nested WHILE/FOR constructs if both optimizations (early exit and decreasing comparison range) are correctly implemented.
Question 10 · Algorithm Optimization & Procedural Pseudocode
6 marks
A logistics analysis system records the hourly package throughput of a sorting facility in a 1D array `Throughput` of size `TotalHours` (with lower bound `1` and upper bound `TotalHours`).

A function is required to find the maximum combined throughput achieved over any continuous window of `WindowSize` hours (where `1 <= WindowSize <= TotalHours`).

To ensure optimal performance, the function must compute the sum of the first window and then update the current sum in a single pass across the remainder of the array by adding the new hour entering the window and subtracting the hour leaving the window, rather than recalculating the sum of all elements in each window.

Write pseudocode for the function `MaxThroughput(Throughput, TotalHours, WindowSize)` returning the maximum window sum as an integer.

[6]
Show answer & marking scheme

Worked solution

A sliding window algorithm allows finding the maximum sum of `WindowSize` contiguous elements in \(O(N)\) time complexity:
1. Initialize `CurrentSum` to `0` and sum the elements from index `1` to `WindowSize`.
2. Initialize `MaxSum` with `CurrentSum`.
3. Loop `Index` from `WindowSize + 1` to `TotalHours`:
- Add `Throughput[Index]` (incoming element) and subtract `Throughput[Index - WindowSize]` (outgoing element) to update `CurrentSum`.
- If `CurrentSum > MaxSum`, update `MaxSum`.
4. Return `MaxSum`.

Marking scheme

1 mark per point (max 6 marks):
- MP1: Correct function header with return type `INTEGER` and declaration of local integer variables.
- MP2: Correct computation of the initial window sum (loop from `1` to `WindowSize`).
- MP3: Correct initialization of `MaxSum` to the initial `CurrentSum`.
- MP4: Single-pass `FOR` loop iterating from `WindowSize + 1` to `TotalHours`.
- MP5: Correct sliding window update formula (`CurrentSum <- CurrentSum + Throughput[Index] - Throughput[Index - WindowSize]`).
- MP6: Conditional check updating `MaxSum` when `CurrentSum > MaxSum`, and `RETURN MaxSum`.
Question 11 · Algorithm Optimization & Procedural Pseudocode
6 marks
A sorted 1D array `SensorLog` contains `NumEntries` integer values in non-decreasing order (where `NumEntries >= 1`). The array bounds are `1` to `NumEntries`.

Due to duplicate sensor pulses, some adjacent values are identical. A procedure `CompressLog` must remove all duplicate values in-place so that each unique value appears only once at the beginning of `SensorLog`.

To achieve optimal linear \(O(n)\) time without nested shifting loops, the algorithm must use two pointers/indices:
- a write pointer (`UniqueCount`) tracking the position of the last stored unique element
- a read pointer (`ReadIndex`) iterating sequentially through the remaining array elements

Write pseudocode for the procedure `CompressLog(SensorLog, NumEntries, UniqueCount)` where `SensorLog` and `UniqueCount` are passed by reference.

[6]
Show answer & marking scheme

Worked solution

Using the two-pointer technique on a sorted array:
1. If `NumEntries < 1`, set `UniqueCount <- 0`.
2. Otherwise, the first element `SensorLog[1]` is always unique, so set `UniqueCount <- 1`.
3. Iterate `ReadIndex` from `2` to `NumEntries`.
4. Whenever `SensorLog[ReadIndex] <> SensorLog[UniqueCount]`, a new distinct value has been encountered:
- Increment `UniqueCount` by `1`.
- Assign `SensorLog[UniqueCount] <- SensorLog[ReadIndex]`.
5. The procedure finishes in a single pass \(O(n)\) with `UniqueCount` holding the number of unique elements.

Marking scheme

1 mark per point (max 6 marks):
- MP1: Correct procedure header with `BYREF SensorLog`, `BYVAL NumEntries`, and `BYREF UniqueCount`.
- MP2: Handling edge case of empty array or initializing `UniqueCount <- 1` for `NumEntries >= 1`.
- MP3: Loop `FOR ReadIndex <- 2 TO NumEntries` (or equivalent `WHILE`).
- MP4: Comparison condition checking if current element differs from last unique element (`SensorLog[ReadIndex] <> SensorLog[UniqueCount]`).
- MP5: Incrementing `UniqueCount` by 1 inside the selection statement.
- MP6: Copying `SensorLog[ReadIndex]` to `SensorLog[UniqueCount]` in-place without nested shifting loops.

Paper 3 Advanced Theory

Answer all questions. Calculators are not permitted.
12 Question · 43.01 marks
Question 1 · open_response
2.67 marks
Simplify the following Boolean expression using Boolean algebra identities and De Morgan's laws. Show all intermediate steps in your working.

\[X = \overline{A + \overline{B \cdot C}} + (B \cdot C)\]
Show answer & marking scheme

Worked solution

Step 1: Apply De Morgan's Law to the first term \(\overline{A + \overline{B \cdot C}}\):
\[\overline{A + \overline{B \cdot C}} = \overline{A} \cdot \overline{\overline{B \cdot C}} = \overline{A} \cdot (B \cdot C)\]

Step 2: Substitute the result back into the expression:
\[X = (\overline{A} \cdot B \cdot C) + (B \cdot C)\]

Step 3: Factor out the common term \((B \cdot C)\):
\[X = (B \cdot C) \cdot (\overline{A} + 1)\]

Step 4: Apply the null element identity \(\overline{A} + 1 = 1\):
\[X = (B \cdot C) \cdot 1 = B \cdot C\]

Marking scheme

1 mark for correctly applying De Morgan's law to the inverted term to obtain \(\overline{A} \cdot B \cdot C\).
1 mark for factoring out \(B \cdot C\) or demonstrating the application of the identity \(\overline{A} + 1 = 1\).
1 mark for the correct final simplified expression: \(B \cdot C\) (or \(B \text{ AND } C\)).
Question 2 · open_response
2.67 marks
The Karnaugh map (K-map) for a logic circuit with inputs \(A, B, C,\) and \(D\) is shown below:

| \(AB \backslash CD\) | 00 | 01 | 11 | 10 |
|---|---|---|---|---|
| 00 | 1 | 1 | 0 | 0 |
| 01 | 1 | 1 | 0 | 0 |
| 11 | 0 | 1 | 1 | 0 |
| 10 | 0 | 1 | 1 | 0 |

(a) Identify the two optimal groups of 1s in the Karnaugh map.
(b) Derive the simplified Sum of Products (SOP) Boolean expression for the output.
Show answer & marking scheme

Worked solution

Step 1: Identify the largest power-of-2 groupings of adjacent 1s:
- Group 1: A group of 4 cells spanning rows \(AB = 00, 01\) and columns \(CD = 00, 01\). In this group, \(A = 0\) and \(C = 0\), while \(B\) and \(D\) vary. This gives the term \(\overline{A} \cdot \overline{C}\).
- Group 2: A group of 4 cells spanning rows \(AB = 11, 10\) and columns \(CD = 01, 11\). In this group, \(A = 1\) and \(D = 1\), while \(B\) and \(C\) vary. This gives the term \(A \cdot D\).

Step 2: Combine the terms using Boolean OR (Sum of Products):
\[\text{Output} = (\overline{A} \cdot \overline{C}) + (A \cdot D)\]

Marking scheme

1 mark for identifying the first 4-cell group covering \(\overline{A} \cdot \overline{C}\) (cells 0000, 0001, 0100, 0101).
1 mark for identifying the second 4-cell group covering \(A \cdot D\) (cells 1101, 1111, 1001, 1011).
1 mark for the correct final simplified SOP expression: \(\overline{A} \cdot \overline{C} + A \cdot D\) (accept equivalent notation such as \(\text{NOT } A \text{ AND NOT } C \text{ OR } A \text{ AND } D\)).
Question 3 · open_response
2.67 marks
Use Boolean algebra and De Morgan's laws to simplify the following expression to its simplest form. Show all your working.

\[Q = \overline{\overline{A} \cdot B + \overline{A \cdot \overline{C}}}\]
Show answer & marking scheme

Worked solution

Step 1: Apply De Morgan's Law to the outermost NOT operation:
\[Q = \overline{\overline{A} \cdot B} \cdot \overline{\overline{A \cdot \overline{C}}}\]

Step 2: Simplify the second factor using double negation \(\overline{\overline{X}} = X\):
\[\overline{\overline{A \cdot \overline{C}}} = A \cdot \overline{C}\]

Step 3: Apply De Morgan's Law to the first factor:
\[\overline{\overline{A} \cdot B} = \overline{\overline{A}} + \overline{B} = A + \overline{B}\]

Step 4: Substitute back and expand using the distributive law:
\[Q = (A + \overline{B}) \cdot (A \cdot \overline{C}) = (A \cdot A \cdot \overline{C}) + (\overline{B} \cdot A \cdot \overline{C})\]

Step 5: Simplify \(A \cdot A = A\):
\[Q = (A \cdot \overline{C}) + (A \cdot \overline{B} \cdot \overline{C})\]

Step 6: Factor out \(A \cdot \overline{C}\) and use the absorption identity \(1 + \overline{B} = 1\):
\[Q = (A \cdot \overline{C}) \cdot (1 + \overline{B}) = A \cdot \overline{C} \cdot 1 = A \cdot \overline{C}\]

Marking scheme

1 mark for correctly applying De Morgan's law to split the outermost expression into \((A + \overline{B}) \cdot (A \cdot \overline{C})\).
1 mark for expanding/distributing to get \((A \cdot \overline{C}) + (A \cdot \overline{B} \cdot \overline{C})\) or factoring appropriately.
1 mark for obtaining the final fully simplified expression: \(A \cdot \overline{C}\) (or \(A \text{ AND NOT } C\)).
Question 4 · free-response
4 marks
A weighted, undirected graph represents a communication network between five servers: \(\text{S}\), \(\text{T}\), \(\text{U}\), \(\text{V}\), and \(\text{W}\).

The edge weights (transmission latencies in ms) are:
- \(\text{S}-\text{T} = 7\), \(\text{S}-\text{U} = 2\)
- \(\text{T}-\text{U} = 3\), \(\text{T}-\text{V} = 1\), \(\text{T}-\text{W} = 8\)
- \(\text{U}-\text{V} = 5\), \(\text{U}-\text{W} = 9\)
- \(\text{V}-\text{W} = 2\)

Dijkstra's algorithm is executed to find the shortest path from start server \(\text{S}\) to destination server \(\text{W}\).

Complete the trace of the algorithm by showing the updated working/tentative distances at each visited node, and state the final shortest path and its total cost. [4]
Show answer & marking scheme

Worked solution

Trace of Dijkstra's algorithm starting at node S:

1. Initial state: S = 0; T = ∞, U = ∞, V = ∞, W = ∞
- Visit S (current distance = 0):
- Update T: min(∞, 0 + 7) = 7 (via S)
- Update U: min(∞, 0 + 2) = 2 (via S)
- Unvisited: U(2), T(7), V(∞), W(∞)

2. Visit U (current distance = 2):
- Update T: min(7, 2 + 3) = 5 (via U)
- Update V: min(∞, 2 + 5) = 7 (via U)
- Update W: min(∞, 2 + 9) = 11 (via U)
- Unvisited: T(5), V(7), W(11)

3. Visit T (current distance = 5):
- Update V: min(7, 5 + 1) = 6 (via T)
- Update W: min(11, 5 + 8) = 11 (via U)
- Unvisited: V(6), W(11)

4. Visit V (current distance = 6):
- Update W: min(11, 6 + 2) = 8 (via V)
- Unvisited: W(8)

5. Visit W (current distance = 8):
- Destination reached.

Final shortest path: S -> U -> T -> V -> W
Total cost = 8 ms.

Marking scheme

1 mark per point:
- 1 mark: Correct tentative distances after visiting U (T=5, V=7, W=11 with correct predecessor tracking).
- 1 mark: Correct tentative distances after visiting T (V updated to 6).
- 1 mark: Correct tentative distances after visiting V (W updated to 8).
- 1 mark: Correct final path (S -> U -> T -> V -> W) AND total cost of 8.
Question 5 · free-response
4 marks
The \(\text{A}^*\) search algorithm uses the evaluation function \(f(n) = g(n) + h(n)\), where \(g(n)\) is the exact cost from the start node to node \(n\), and \(h(n)\) is the heuristic estimate from node \(n\) to the goal node \(\text{G}\).

A search graph has start node \(\text{A}\) and goal node \(\text{G}\).

Heuristic values \(h(n)\):
- \(h(\text{A}) = 7\)
- \(h(\text{B}) = 6\)
- \(h(\text{C}) = 4\)
- \(h(\text{D}) = 2\)
- \(h(\text{G}) = 0\)

Directed edge costs:
- \(\text{A} \rightarrow \text{B} = 2\)
- \(\text{A} \rightarrow \text{C} = 4\)
- \(\text{B} \rightarrow \text{C} = 1\)
- \(\text{B} \rightarrow \text{D} = 7\)
- \(\text{C} \rightarrow \text{D} = 3\)
- \(\text{C} \rightarrow \text{G} = 8\)
- \(\text{D} \rightarrow \text{G} = 3\)

Trace the execution of the \(\text{A}^*\) algorithm. State the order in which nodes are expanded, their \(f(n)\) values when expanded, and identify the final path found and its total cost. [4]
Show answer & marking scheme

Worked solution

Trace of A* algorithm:

1. Initial state: Open List = { A(g=0, h=7, f=7) }
- Expand A:
- Generate B: g = 0 + 2 = 2, h = 6, f = 8 (parent A)
- Generate C: g = 0 + 4 = 4, h = 4, f = 8 (parent A)
- Open List = { B(f=8, g=2), C(f=8, g=4) }

2. Expand B (f=8, g=2):
- Generate C: g = 2 + 1 = 3 < 4 -> update C: g = 3, h = 4, f = 7 (parent B)
- Generate D: g = 2 + 7 = 9, h = 2, f = 11 (parent B)
- Open List = { C(f=7, g=3), D(f=11, g=9) }

3. Expand C (f=7, g=3):
- Generate D: g = 3 + 3 = 6 < 9 -> update D: g = 6, h = 2, f = 8 (parent C)
- Generate G: g = 3 + 8 = 11, h = 0, f = 11 (parent C)
- Open List = { D(f=8, g=6), G(f=11, g=11) }

4. Expand D (f=8, g=6):
- Generate G: g = 6 + 3 = 9 < 11 -> update G: g = 9, h = 0, f = 9 (parent D)
- Open List = { G(f=9, g=9) }

5. Expand / Select G (f=9, g=9):
- Goal reached.

Order of node expansion: A -> B -> C -> D -> G
Final path: A -> B -> C -> D -> G
Total path cost = 9.

Marking scheme

1 mark per point:
- 1 mark: Correct evaluation of children of A and selection of next node (B or C with f=8).
- 1 mark: Correct update of C via B resulting in f(C) = 7 (g=3, h=4).
- 1 mark: Correct expansion of C and update of D resulting in f(D) = 8 (g=6, h=2).
- 1 mark: Correct expansion of D and selection of G with total cost 9 and path A -> B -> C -> D -> G.
Question 6 · standard
5 marks
A logistics management system uses object-oriented programming (OOP) to handle deliveries.

The base class `Package` has the following attributes and methods:
- `PackageID` : `STRING` (Private)
- `WeightKg` : `REAL` (Private)
- `Constructor(ID : STRING, Weight : REAL)`
- `GetWeight() RETURNS REAL`

A subclass `ExpressPackage` inherits from `Package`. It has an additional private attribute:
- `DeliveryDays` : `INTEGER` (the guaranteed maximum days for delivery)

Write pseudocode to define the complete class `ExpressPackage`, including:
- the class header and inheritance
- declaration of the attribute `DeliveryDays`
- the constructor `NEW()` which accepts `ID`, `Weight`, and `DeliveryDays` as parameters and uses the `SUPER` constructor
- the `get` method `GetDeliveryDays()` which returns the delivery days.

[5]
Show answer & marking scheme

Worked solution

Pseudocode implementation:

```text
CLASS ExpressPackage INHERITS Package
PRIVATE DeliveryDays : INTEGER

PUBLIC PROCEDURE NEW(ID : STRING, Weight : REAL, Days : INTEGER)
SUPER.NEW(ID, Weight)
DeliveryDays <- Days
ENDPROCEDURE

PUBLIC FUNCTION GetDeliveryDays() RETURNS INTEGER
RETURN DeliveryDays
ENDFUNCTION
ENDCLASS
```

Marking scheme

1 mark per marking point (MP) up to max 5:
- MP1: Correct class header showing inheritance from `Package` (`CLASS ExpressPackage INHERITS Package`) and closing `ENDCLASS`.
- MP2: Correct declaration of private integer attribute `DeliveryDays` (`PRIVATE DeliveryDays : INTEGER`).
- MP3: Constructor declaration with three parameters of correct types (`ID : STRING, Weight : REAL, Days : INTEGER`).
- MP4: Invoking superclass constructor using `SUPER.NEW(ID, Weight)` or `SUPER(ID, Weight)`.
- MP5: Assigning `DeliveryDays` in constructor AND defining `GetDeliveryDays()` returning `DeliveryDays` with correct return type `INTEGER`.
Question 7 · standard
5 marks
A warehouse system stores product records in a random-access file named `Inventory.dat`.

The record structure `ProductRecord` is defined as follows:
```text
TYPE ProductRecord
DECLARE ProductCode : STRING
DECLARE ItemName : STRING
DECLARE UnitsInStock: INTEGER
DECLARE UnitPrice : REAL
ENDTYPE
```

A hashing function `HashKey(Code : STRING) RETURNS INTEGER` calculates the record position within the file.

Write pseudocode for a procedure `UpdateStock(Code : STRING, QuantityPurchased : INTEGER)` to:
1. Open the file `Inventory.dat` for random access.
2. Use `HashKey()` and `SEEK` to locate the record corresponding to `Code`.
3. Read the existing `ProductRecord` from the file.
4. Increase `UnitsInStock` by `QuantityPurchased`.
5. Write the modified record back to the exact same position in the file.
6. Close the file.

[5]
Show answer & marking scheme

Worked solution

Pseudocode implementation:

```text
PROCEDURE UpdateStock(Code : STRING, QuantityPurchased : INTEGER)
DECLARE CurrentProduct : ProductRecord
DECLARE RecordPosition : INTEGER

RecordPosition <- HashKey(Code)
OPENFILE "Inventory.dat" FOR RANDOM
SEEK "Inventory.dat", RecordPosition
GETRECORD "Inventory.dat", CurrentProduct

CurrentProduct.UnitsInStock <- CurrentProduct.UnitsInStock + QuantityPurchased

SEEK "Inventory.dat", RecordPosition
PUTRECORD "Inventory.dat", CurrentProduct
CLOSEFILE "Inventory.dat"
ENDPROCEDURE
```

Marking scheme

1 mark per marking point (MP) up to max 5:
- MP1: Opening file for random access (`OPENFILE "Inventory.dat" FOR RANDOM`) and closing the file (`CLOSEFILE "Inventory.dat"`).
- MP2: Calculating record position using `HashKey(Code)` and performing initial `SEEK "Inventory.dat", RecordPosition`.
- MP3: Reading record into variable using `GETRECORD "Inventory.dat", CurrentProduct`.
- MP4: Correctly incrementing `CurrentProduct.UnitsInStock` by `QuantityPurchased`.
- MP5: Performing second `SEEK` to the same position and writing record back using `PUTRECORD "Inventory.dat", CurrentProduct`.
Question 8 · standard
5 marks
A weather monitoring system writes telemetry readings to a serial text file named `Telemetry.txt`. Each line contains a single numerical temperature value stored as text (e.g. `"21.4"`).

Write pseudocode for a function `AverageTemperature() RETURNS REAL` that:
- Attempts to open and read all temperature values from `Telemetry.txt` using structured exception handling (`TRY ... EXCEPT ... ENDTRY`).
- Calculates and returns the average (mean) temperature as a `REAL`.
- If an error occurs during file access (or if the file is missing/empty), the function catches the exception, outputs `"Error reading telemetry data"`, and returns `-999.0`.
- Ensures the file is closed if it was opened.

[5]
Show answer & marking scheme

Worked solution

Pseudocode implementation:

```text
FUNCTION AverageTemperature() RETURNS REAL
DECLARE Total : REAL
DECLARE Count : INTEGER
DECLARE LineValue : STRING
DECLARE CurrentTemp : REAL

Total <- 0.0
Count <- 0

TRY
OPENFILE "Telemetry.txt" FOR READ
WHILE NOT EOF("Telemetry.txt")
READFILE "Telemetry.txt", LineValue
CurrentTemp <- STRING_TO_REAL(LineValue)
Total <- Total + CurrentTemp
Count <- Count + 1
ENDWHILE
CLOSEFILE "Telemetry.txt"

IF Count > 0 THEN
RETURN Total / Count
ELSE
RETURN -999.0
ENDIF
EXCEPT
OUTPUT "Error reading telemetry data"
RETURN -999.0
ENDTRY
ENDFUNCTION
```

Marking scheme

1 mark per marking point (MP) up to max 5:
- MP1: Initialising sum and count variables to 0 / 0.0 AND wrapping file operations within a `TRY ... EXCEPT ... ENDTRY` block.
- MP2: Opening `Telemetry.txt` for `READ` and using a `WHILE NOT EOF("Telemetry.txt")` loop with `CLOSEFILE "Telemetry.txt"`.
- MP3: Reading each line with `READFILE` and converting/accumulating values to total and incrementing count.
- MP4: Calculating and returning the average (`Total / Count`) when `Count > 0`.
- MP5: `EXCEPT` block outputs error message `"Error reading telemetry data"` and returns `-999.0` (also handles division by zero / empty file returning `-999.0`).
Question 9 · Advanced Systems & Networking Recall
3 marks
BitTorrent is a protocol used for peer-to-peer (P2P) file sharing across the internet.

Describe the role of each of the following components in a BitTorrent network:

(i) Tracker [1]
(ii) Peer [1]
(iii) Seeder [1]
Show answer & marking scheme

Worked solution

(i) Tracker:
Maintains a directory of all connected nodes participating in the swarm and distributes their network details (IP addresses/ports) so that nodes can locate and establish direct peer-to-peer connections with one another.

(ii) Peer:
A participating client node in the swarm that is currently downloading chunks of the file while concurrently uploading already downloaded chunks to other active nodes.

(iii) Seeder:
A node that possesses the complete copy (100%) of the shared file and remains connected solely to upload pieces to other downloading peers.

Marking scheme

1 mark per correct description:

(i) Tracker [1 mark]:
- Coordinates/manages the swarm by keeping a record of all participating peers and sharing their IP addresses / helps peers locate one another.
(Note: Do not accept that the tracker stores/transfers the actual file data).

(ii) Peer [1 mark]:
- A node/computer that downloads file chunks while simultaneously uploading chunks to other nodes in the swarm.

(iii) Seeder [1 mark]:
- A node/computer that has the entire/complete file and uploads it to others (without needing to download anything further).
Question 10 · Advanced Systems & Networking Recall
3 marks
An operating system uses paging to manage virtual memory.

(a) Explain what is meant by the term disk thrashing. [2]

(b) State one method that can be used to prevent or reduce disk thrashing. [1]
Show answer & marking scheme

Worked solution

(a) Disk thrashing arises when the main memory (RAM) is insufficient to hold the working sets of all running processes. This leads to a continuous sequence of page faults, forcing the operating system into a perpetual loop of reading pages from secondary storage (swap/paging space) and writing existing pages back out. As a consequence, the CPU spends virtually all its processing time handling I/O operations and page swaps rather than making progress on running tasks, causing severe system slowdown.

(b) Installing additional physical RAM increases the space available for pages, significantly reducing the frequency of page faults. Alternatively, terminating non-essential concurrent processes reduces demand on memory.

Marking scheme

(a) [Max 2 marks]:
- 1 mark for: A state where the OS spends excessive/more time swapping/moving pages between RAM and secondary storage (disk/swap space) than executing instructions / processing data.
- 1 mark for: Caused by a high rate of page faults / physical memory being insufficient to hold the working sets of all active processes.

(b) [1 mark]:
- Add more physical RAM / memory.
- Close active programs / reduce the number of running processes (reduce degree of multiprogramming).
- Optimize the page replacement algorithm.
Question 11 · Advanced Systems & Networking Recall
3 marks
Digital certificates are used to establish secure communication sessions using TLS/SSL.

Describe how a client web browser verifies the authenticity and integrity of a web server's digital certificate. [3]
Show answer & marking scheme

Worked solution

When a web server provides its digital certificate to a browser:
1. The browser locates the digital signature generated by the Certificate Authority (CA) on the certificate.
2. The browser accesses the trusted public key of the signing CA from its built-in root store and uses this public key to decrypt the digital signature, yielding the original digest/hash.
3. The browser calculates an independent hash of the certificate's plain contents using the specified hashing algorithm and checks if it matches the decrypted hash. A match confirms the certificate was signed by a genuine CA and has not been altered in transit.

Marking scheme

1 mark per point up to a maximum of 3:
- MP1: The browser obtains the Certificate Authority's (CA) public key (stored in the browser / operating system trust store).
- MP2: The browser decrypts the digital signature on the certificate using the CA's public key to extract the decrypted hash / digest.
- MP3: The browser generates a new cryptographic hash of the certificate contents / data (using the same hashing algorithm).
- MP4: The browser compares the generated hash with the decrypted hash; matching hashes prove authenticity and that data has not been modified/tampered with.
Question 12 · Advanced Systems & Networking Recall
3 marks
(a) State what is meant by a virtual machine. [1]

(b) Explain two benefits of using a virtual machine when developing and testing software. [2]
Show answer & marking scheme

Worked solution

(a) A virtual machine is a software program or environment that replicates/emulates the hardware components and architecture of a physical computer, enabling a guest operating system to run independently on top of a host operating system/hypervisor.

(b) Benefit 1 (Sandboxing/Safety): The guest environment is isolated from the host machine. If an experimental piece of software causes a critical kernel panic, data corruption, or installs malware, the host machine remains completely unaffected.
Benefit 2 (Portability & Multi-OS Testing): Developers can quickly test an application across various target environments (e.g., Linux, Windows 10, Windows 11) using snapshots and multiple VM configurations on a single development workstation, saving hardware expenditure and configuration time.

Marking scheme

(a) [1 mark]:
- Software that emulates/simulates the architecture and functionality of a physical computer / an isolated software container that executes a guest operating system.

(b) [Max 2 marks, 1 mark per explained benefit]:
- Isolation / Sandboxing: Testing untrusted or unstable code cannot crash, corrupt, or compromise the host system's hardware/OS.
- Multiple operating systems / Cross-platform testing: Allows testing under different OSs and configurations on a single physical machine without purchasing extra hardware.
- Snapshot / Rollback capability: The state of the VM can be saved and restored quickly to a clean state after destructive tests.
(Accept other valid benefits in the context of software development/testing).

Paper 4 Practical

Carry out every instruction in each task. Save code and screenshots into evidence.docx using Python, Java, or VB.NET.
14 Question · 68 marks
Question 1 · Code Implementation
4.5 marks
A program contains a global 1D array named `Scores` containing 8 integer elements.

Write program code for the function `InsertionSort()` that takes the 1D integer array as a parameter and sorts the elements into ascending numerical order using the insertion sort algorithm.

The function must return the sorted array.

Save your program code and take a screenshot of the function implementation to save in your evidence document.
Show answer & marking scheme

Worked solution

### Python Implementation:
```python
def InsertionSort(Scores):
for i in range(1, len(Scores)):
key = Scores[i]
j = i - 1
while j >= 0 and Scores[j] > key:
Scores[j + 1] = Scores[j]
j -= 1
Scores[j + 1] = key
return Scores
```

### Java Implementation:
```java
public static int[] InsertionSort(int[] Scores) {
for (int i = 1; i < Scores.length; i++) {
int key = Scores[i];
int j = i - 1;
while (j >= 0 && Scores[j] > key) {
Scores[j + 1] = Scores[j];
j--;
}
Scores[j + 1] = key;
}
return Scores;
}
```

### VB.NET Implementation:
```vb
Function InsertionSort(ByVal Scores() As Integer) As Integer()
Dim i, j, key As Integer
For i = 1 To Scores.Length - 1
key = Scores(i)
j = i - 1
While j >= 0 AndAlso Scores(j) > key
Scores(j + 1) = Scores(j)
j = j - 1
End While
Scores(j + 1) = key
Next i
Return Scores
End Function
```

Marking scheme

1 mark: Function header taking 1D array parameter and returning an array / updated structure.
1 mark: Outer loop iterating from index 1 to the end of the array.
1 mark: Storing current value (`key`) and correctly initialising inner loop counter (`j = i - 1`).
1 mark: Inner `while` loop with correct boundary check (`j >= 0`) and comparison (`Scores[j] > key`) shifting elements right (`Scores[j+1] = Scores[j]`).
0.5 mark: Inserting `key` at the correct target index (`Scores[j+1] = key`).
Question 2 · Code Implementation
4.5 marks
A program stores a sorted list of 10 customer ID strings in an array named `CustomerIDList`.

Write program code for a function `BinarySearch(SearchArray, TargetID)` that:
- takes the sorted 1D string array `SearchArray` and a string `TargetID` to search for as parameters
- performs an iterative binary search
- returns the integer index of `TargetID` if found, or `-1` if `TargetID` does not exist in the array.

Save your program code into your evidence document.
Show answer & marking scheme

Worked solution

### Python Implementation:
```python
def BinarySearch(SearchArray, TargetID):
low = 0
high = len(SearchArray) - 1
while low <= high:
mid = (low + high) // 2
if SearchArray[mid] == TargetID:
return mid
elif SearchArray[mid] < TargetID:
low = mid + 1
else:
high = mid - 1
return -1
```

### Java Implementation:
```java
public static int BinarySearch(String[] SearchArray, String TargetID) {
int low = 0;
int high = SearchArray.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
int cmp = SearchArray[mid].compareTo(TargetID);
if (cmp == 0) {
return mid;
} else if (cmp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
```

### VB.NET Implementation:
```vb
Function BinarySearch(ByVal SearchArray() As String, ByVal TargetID As String) As Integer
Dim low As Integer = 0
Dim high As Integer = SearchArray.Length - 1
Dim mid As Integer
While low <= high
mid = (low + high) \ 2
If SearchArray(mid) = TargetID Then
Return mid
ElseIf SearchArray(mid) < TargetID Then
low = mid + 1
Else
high = mid - 1
End If
End While
Return -1
End Function
```

Marking scheme

1 mark: Function header defining two parameters (array and search target) and returning an integer.
1 mark: Initialising `low` to 0 and `high` to upper index bound (`length - 1`).
1 mark: Loop condition `low <= high` and calculation of `mid` using integer division.
1 mark: Correct conditional statements comparing midpoint element to `TargetID` and updating `low` (`mid + 1`) or `high` (`mid - 1`).
0.5 mark: Returning `mid` on a match and `-1` if not found after the loop terminates.
Question 3 · Code Implementation
4.5 marks
An application stores student registration numbers and test results in two 1D parallel arrays:
- `StudentNames` : array of 10 strings
- `StudentMarks` : array of 10 integers

Write program code for a procedure `BubbleSortParallel()` that sorts both arrays in descending order of `StudentMarks` (highest mark first), ensuring that each student's name remains paired with their corresponding mark.

Include an optimisation to stop the sort if no swaps are made during a pass.

Save your code into your evidence document.
Show answer & marking scheme

Worked solution

### Python Implementation:
```python
def BubbleSortParallel(StudentNames, StudentMarks):
n = len(StudentMarks)
for i in range(n - 1):
swapped = False
for j in range(0, n - i - 1):
if StudentMarks[j] < StudentMarks[j + 1]:
# Swap marks
temp_mark = StudentMarks[j]
StudentMarks[j] = StudentMarks[j + 1]
StudentMarks[j + 1] = temp_mark
# Swap corresponding names
temp_name = StudentNames[j]
StudentNames[j] = StudentNames[j + 1]
StudentNames[j + 1] = temp_name
swapped = True
if not swapped:
break
```

### Java Implementation:
```java
public static void BubbleSortParallel(String[] StudentNames, int[] StudentMarks) {
int n = StudentMarks.length;
for (int i = 0; i < n - 1; i++) {
boolean swapped = false;
for (int j = 0; j < n - i - 1; j++) {
if (StudentMarks[j] < StudentMarks[j + 1]) {
int tempMark = StudentMarks[j];
StudentMarks[j] = StudentMarks[j + 1];
StudentMarks[j + 1] = tempMark;

String tempName = StudentNames[j];
StudentNames[j] = StudentNames[j + 1];
StudentNames[j + 1] = tempName;

swapped = true;
}
}
if (!swapped) {
break;
}
}
}
```

### VB.NET Implementation:
```vb
Sub BubbleSortParallel(ByRef StudentNames() As String, ByRef StudentMarks() As Integer)
Dim n As Integer = StudentMarks.Length
Dim swapped As Boolean
For i As Integer = 0 To n - 2
swapped = False
For j As Integer = 0 To n - i - 2
If StudentMarks(j) < StudentMarks(j + 1) Then
Dim tempMark As Integer = StudentMarks(j)
StudentMarks(j) = StudentMarks(j + 1)
StudentMarks(j + 1) = tempMark

Dim tempName As String = StudentNames(j)
StudentNames(j) = StudentNames(j + 1)
StudentNames(j + 1) = tempName

swapped = True
End If
Next j
If Not swapped Then
Exit For
End If
Next i
End Sub
```

Marking scheme

1 mark: Nested loop structure iterating through the array bounds correctly.
1 mark: Comparison testing if current mark is less than next mark (`StudentMarks[j] < StudentMarks[j + 1]`) for descending order.
1 mark: Swapping elements in `StudentMarks` using a temporary variable / tuple swap.
1 mark: Synchronously swapping elements at corresponding indices in `StudentNames`.
0.5 mark: Boolean flag (`swapped`) correctly reset per pass and checked to terminate early if no swaps occurred.
Question 4 · Code Implementation
4.5 marks
A warehouse management program maintains a 2D integer array `StockData` with dimensions `[15, 3]`, where:
- column index `0` represents the `ItemID`
- column index `1` represents the `QuantityInStock`
- column index `2` represents the `ReorderLevel`

Write program code for a function `FindRestockItems(StockData)` that:
- iterates through all 15 rows of the 2D array
- identifies every item where `QuantityInStock <= ReorderLevel`
- outputs the `ItemID` and current `QuantityInStock` of each matching item to the console
- returns the total count of items that need restocking.

Save your program code into your evidence document.
Show answer & marking scheme

Worked solution

### Python Implementation:
```python
def FindRestockItems(StockData):
restock_count = 0
for row in range(len(StockData)):
item_id = StockData[row][0]
quantity = StockData[row][1]
reorder_lvl = StockData[row][2]
if quantity <= reorder_lvl:
print(f"Item ID: {item_id}, Quantity: {quantity}")
restock_count += 1
return restock_count
```

### Java Implementation:
```java
public static int FindRestockItems(int[][] StockData) {
int restockCount = 0;
for (int row = 0; row < StockData.length; row++) {
int itemId = StockData[row][0];
int quantity = StockData[row][1];
int reorderLvl = StockData[row][2];
if (quantity <= reorderLvl) {
System.out.println("Item ID: " + itemId + ", Quantity: " + quantity);
restockCount++;
}
}
return restockCount;
}
```

### VB.NET Implementation:
```vb
Function FindRestockItems(ByVal StockData(,) As Integer) As Integer
Dim restockCount As Integer = 0
Dim numRows As Integer = StockData.GetLength(0)
For row As Integer = 0 To numRows - 1
Dim itemId As Integer = StockData(row, 0)
Dim quantity As Integer = StockData(row, 1)
Dim reorderLvl As Integer = StockData(row, 2)
If quantity <= reorderLvl Then
Console.WriteLine("Item ID: " & itemId & ", Quantity: " & quantity)
restockCount += 1
End If
Next row
Return restockCount
End Function
```

Marking scheme

1 mark: Function header taking 2D array parameter and returning an integer.
1 mark: Loop iterating through all rows (0 to 14 or length of outer dimension).
1 mark: Correct indexing of 2D array accessing column 1 (`QuantityInStock`) and column 2 (`ReorderLevel`) with condition `QuantityInStock <= ReorderLevel`.
1 mark: Correct console output displaying the `ItemID` (column 0) and `QuantityInStock` for matching items.
0.5 mark: Counter correctly incremented and returned by the function.
Question 5 · practical
5 marks
A program is being developed to process environmental sensor records from a text file named `WeatherLog.txt`.

An object-oriented approach is used.

(a) Write program code to define the class `WeatherRecord`.

The class has the following private attributes:
- `RecordedDate` (String)
- `Temperature` (Real)
- `Humidity` (Integer)

The class has the following methods:
- `Constructor(DateValue, TempValue, HumValue)`: initialises the private attributes with the parameter values.
- `GetDate()`: returns `RecordedDate`.
- `GetTemperature()`: returns `Temperature`.
- `GetHumidity()`: returns `Humidity`.
- `Validate()`: returns `TRUE` if `Temperature` is between -50.0 and 60.0 inclusive, and `Humidity` is between 0 and 100 inclusive. Otherwise, it returns `FALSE`.

Save your program code.
[5]
Show answer & marking scheme

Worked solution

### Python 3
```python
class WeatherRecord:
def __init__(self, DateValue, TempValue, HumValue):
self.__RecordedDate = str(DateValue)
self.__Temperature = float(TempValue)
self.__Humidity = int(HumValue)

def GetDate(self):
return self.__RecordedDate

def GetTemperature(self):
return self.__Temperature

def GetHumidity(self):
return self.__Humidity

def Validate(self):
if -50.0 <= self.__Temperature <= 60.0 and 0 <= self.__Humidity <= 100:
return True
return False
```

### Java
```java
public class WeatherRecord {
private String RecordedDate;
private double Temperature;
private int Humidity;

public WeatherRecord(String DateValue, double TempValue, int HumValue) {
this.RecordedDate = DateValue;
this.Temperature = TempValue;
this.Humidity = HumValue;
}

public String GetDate() {
return this.RecordedDate;
}

public double GetTemperature() {
return this.Temperature;
}

public int GetHumidity() {
return this.Humidity;
}

public boolean Validate() {
if (this.Temperature >= -50.0 && this.Temperature <= 60.0 && this.Humidity >= 0 && this.Humidity <= 100) {
return true;
}
return false;
}
}
```

### VB.NET
```vb
Public Class WeatherRecord
Private RecordedDate As String
Private Temperature As Double
Private Humidity As Integer

Public Sub New(ByVal DateValue As String, ByVal TempValue As Double, ByVal HumValue As Integer)
RecordedDate = DateValue
Temperature = TempValue
Humidity = HumValue
End Sub

Public Function GetDate() As String
Return RecordedDate
End Function

Public Function GetTemperature() As Double
Return Temperature
End Function

Public Function GetHumidity() As Integer
Return Humidity
End Function

Public Function Validate() As Boolean
If Temperature >= -50.0 And Temperature <= 60.0 And Humidity >= 0 And Humidity <= 100 Then
Return True
Else
Return False
End If
End Function
End Class
```

Marking scheme

1 mark: Class header and private attribute declarations with correct data types
1 mark: Constructor definition taking 3 parameters and assigning to private attributes
1 mark: Getter methods `GetDate()`, `GetTemperature()`, `GetHumidity()` returning correct attributes
1 mark: `Validate()` checking `Temperature` range (-50.0 to 60.0 inclusive)
1 mark: `Validate()` checking `Humidity` range (0 to 100 inclusive) and returning boolean results
Question 6 · practical
5 marks
A logistics warehouse tracks parcel records. A text file named `Parcels.txt` stores details of incoming parcels in sets of three consecutive lines:
- Line 1: Tracking Code (String)
- Line 2: Weight in kg (Real)
- Line 3: Express Delivery flag (Boolean, represented as `TRUE` or `FALSE`)

(a) Write program code to define a class `Parcel`.

The class has private attributes `TrackingCode`, `Weight`, and `IsExpress`.

The class methods are:
- `Constructor(Code, W, Express)`: initialises the private attributes.
- `GetTrackingCode()`, `GetWeight()`, `GetIsExpress()`: getter methods for each attribute.
- `IsValidCode()`: returns `TRUE` if `TrackingCode` has a length of exactly 6 characters and starts with `'PK'`, otherwise returns `FALSE`.

Save your program code.
[5]
Show answer & marking scheme

Worked solution

### Python 3
```python
class Parcel:
def __init__(self, Code, W, Express):
self.__TrackingCode = str(Code)
self.__Weight = float(W)
self.__IsExpress = bool(Express)

def GetTrackingCode(self):
return self.__TrackingCode

def GetWeight(self):
return self.__Weight

def GetIsExpress(self):
return self.__IsExpress

def IsValidCode(self):
if len(self.__TrackingCode) == 6 and self.__TrackingCode.startswith("PK"):
return True
return False
```

### Java
```java
public class Parcel {
private String TrackingCode;
private double Weight;
private boolean IsExpress;

public Parcel(String Code, double W, boolean Express) {
this.TrackingCode = Code;
this.Weight = W;
this.IsExpress = Express;
}

public String GetTrackingCode() {
return this.TrackingCode;
}

public double GetWeight() {
return this.Weight;
}

public boolean GetIsExpress() {
return this.IsExpress;
}

public boolean IsValidCode() {
if (this.TrackingCode.length() == 6 && this.TrackingCode.startsWith("PK")) {
return true;
}
return false;
}
}
```

### VB.NET
```vb
Public Class Parcel
Private TrackingCode As String
Private Weight As Double
Private IsExpress As Boolean

Public Sub New(ByVal Code As String, ByVal W As Double, ByVal Express As Boolean)
TrackingCode = Code
Weight = W
IsExpress = Express
End Sub

Public Function GetTrackingCode() As String
Return TrackingCode
End Function

Public Function GetWeight() As Double
Return Weight
End Function

Public Function GetIsExpress() As Boolean
Return IsExpress
End Function

Public Function IsValidCode() As Boolean
If TrackingCode.Length = 6 AndAlso TrackingCode.StartsWith("PK") Then
Return True
Else
Return False
End If
End Function
End Class
```

Marking scheme

1 mark: Class header and 3 private attributes defined with appropriate data types
1 mark: Constructor initialising all three attributes correctly
1 mark: All three getter methods implemented and returning corresponding attributes
1 mark: Length validation check for exactly 6 characters in `IsValidCode()`
1 mark: Prefix validation check starting with `'PK'` and returning boolean
Question 7 · practical
5 marks
A retail management program reads inventory items from a text file.

(a) Write program code to define the class `InventoryItem`.

The class has the following private attributes:
- `SKU` (String)
- `StockLevel` (Integer)
- `ReorderThreshold` (Integer)

The class has the following methods:
- `Constructor(NewSKU, NewStock, NewThreshold)`: initialises all private attributes.
- `GetSKU()`: returns `SKU`.
- `GetStockLevel()`: returns `StockLevel`.
- `NeedsReorder()`: returns `TRUE` if `StockLevel` is less than or equal to `ReorderThreshold`, otherwise `FALSE`.
- `ValidateData()`: returns `TRUE` if `SKU` is not empty (length > 0) and `StockLevel >= 0` and `ReorderThreshold >= 0`. Otherwise, returns `FALSE`.

Save your program code.
[5]
Show answer & marking scheme

Worked solution

### Python 3
```python
class InventoryItem:
def __init__(self, NewSKU, NewStock, NewThreshold):
self.__SKU = str(NewSKU)
self.__StockLevel = int(NewStock)
self.__ReorderThreshold = int(NewThreshold)

def GetSKU(self):
return self.__SKU

def GetStockLevel(self):
return self.__StockLevel

def NeedsReorder(self):
return self.__StockLevel <= self.__ReorderThreshold

def ValidateData(self):
if len(self.__SKU.strip()) > 0 and self.__StockLevel >= 0 and self.__ReorderThreshold >= 0:
return True
return False
```

### Java
```java
public class InventoryItem {
private String SKU;
private int StockLevel;
private int ReorderThreshold;

public InventoryItem(String NewSKU, int NewStock, int NewThreshold) {
this.SKU = NewSKU;
this.StockLevel = NewStock;
this.ReorderThreshold = NewThreshold;
}

public String GetSKU() {
return this.SKU;
}

public int GetStockLevel() {
return this.StockLevel;
}

public boolean NeedsReorder() {
return this.StockLevel <= this.ReorderThreshold;
}

public boolean ValidateData() {
if (this.SKU != null && this.SKU.trim().length() > 0 && this.StockLevel >= 0 && this.ReorderThreshold >= 0) {
return true;
}
return false;
}
}
```

### VB.NET
```vb
Public Class InventoryItem
Private SKU As String
Private StockLevel As Integer
Private ReorderThreshold As Integer

Public Sub New(ByVal NewSKU As String, ByVal NewStock As Integer, ByVal NewThreshold As Integer)
SKU = NewSKU
StockLevel = NewStock
ReorderThreshold = NewThreshold
End Sub

Public Function GetSKU() As String
Return SKU
End Function

Public Function GetStockLevel() As Integer
Return StockLevel
End Function

Public Function NeedsReorder() As Boolean
Return StockLevel <= ReorderThreshold
End Function

Public Function ValidateData() As Boolean
If SKU IsNot Nothing AndAlso SKU.Trim().Length > 0 AndAlso StockLevel >= 0 AndAlso ReorderThreshold >= 0 Then
Return True
Else
Return False
End If
End Function
End Class
```

Marking scheme

1 mark: Class definition with private attributes `SKU`, `StockLevel`, and `ReorderThreshold`
1 mark: Constructor setting all three attributes properly
1 mark: `GetSKU()` and `GetStockLevel()` methods correctly returning attributes
1 mark: `NeedsReorder()` method correctly evaluating `StockLevel <= ReorderThreshold`
1 mark: `ValidateData()` checking presence of SKU (length > 0) and non-negative values for both numerical attributes
Question 8 · practical
5 marks
A public library uses a program to manage borrowing records.

(a) Write program code to define the class `BorrowRecord`.

The class has the following private attributes:
- `MemberID` (String)
- `BookISBN` (String)
- `LoanDays` (Integer)

The class has the following methods:
- `Constructor(Member, ISBN, Days)`: initialises private attributes.
- `GetMemberID()`: returns `MemberID`.
- `GetISBN()`: returns `BookISBN`.
- `GetLoanDays()`: returns `LoanDays`.
- `ValidateRecord()`: returns `TRUE` if `LoanDays` is between 1 and 30 inclusive AND `BookISBN` has a length of either 10 or 13 characters. Otherwise, it returns `FALSE`.

Save your program code.
[5]
Show answer & marking scheme

Worked solution

### Python 3
```python
class BorrowRecord:
def __init__(self, Member, ISBN, Days):
self.__MemberID = str(Member)
self.__BookISBN = str(ISBN)
self.__LoanDays = int(Days)

def GetMemberID(self):
return self.__MemberID

def GetISBN(self):
return self.__BookISBN

def GetLoanDays(self):
return self.__LoanDays

def ValidateRecord(self):
isbn_len = len(self.__BookISBN.strip())
if (1 <= self.__LoanDays <= 30) and (isbn_len == 10 or isbn_len == 13):
return True
return False
```

### Java
```java
public class BorrowRecord {
private String MemberID;
private String BookISBN;
private int LoanDays;

public BorrowRecord(String Member, String ISBN, int Days) {
this.MemberID = Member;
this.BookISBN = ISBN;
this.LoanDays = Days;
}

public String GetMemberID() {
return this.MemberID;
}

public String GetISBN() {
return this.BookISBN;
}

public int GetLoanDays() {
return this.LoanDays;
}

public boolean ValidateRecord() {
int len = (this.BookISBN != null) ? this.BookISBN.trim().length() : 0;
if (this.LoanDays >= 1 && this.LoanDays <= 30 && (len == 10 || len == 13)) {
return true;
}
return false;
}
}
```

### VB.NET
```vb
Public Class BorrowRecord
Private MemberID As String
Private BookISBN As String
Private LoanDays As Integer

Public Sub New(ByVal Member As String, ByVal ISBN As String, ByVal Days As Integer)
MemberID = Member
BookISBN = ISBN
LoanDays = Days
End Sub

Public Function GetMemberID() As String
Return MemberID
End Function

Public Function GetISBN() As String
Return BookISBN
End Function

Public Function GetLoanDays() As Integer
Return LoanDays
End Function

Public Function ValidateRecord() As Boolean
Dim length As Integer = 0
If BookISBN IsNot Nothing Then
length = BookISBN.Trim().Length
End If
If LoanDays >= 1 AndAlso LoanDays <= 30 AndAlso (length = 10 OrElse length = 13) Then
Return True
Else
Return False
End If
End Function
End Class
```

Marking scheme

1 mark: Class header and 3 private attributes with appropriate data types
1 mark: Constructor method taking 3 parameters and storing them in private attributes
1 mark: Three getter functions returning `MemberID`, `BookISBN`, and `LoanDays`
1 mark: `ValidateRecord()` checking `LoanDays` is between 1 and 30 inclusive
1 mark: `ValidateRecord()` checking `BookISBN` length is 10 or 13, returning appropriate boolean
Question 9 · practical
5 marks
A banking simulation program processes financial transactions.

(a) Write program code to define the class `AccountTransaction`.

The class has the following private attributes:
- `TransactionID` (String)
- `AccountType` (Char)
- `Amount` (Real)

The class has the following methods:
- `Constructor(TransID, AccType, TransAmount)`: assigns parameter values to private attributes.
- `GetTransactionID()`: returns `TransactionID`.
- `GetAccountType()`: returns `AccountType`.
- `GetAmount()`: returns `Amount`.
- `ValidateTransaction()`: returns `TRUE` if `AccountType` is either `'S'` (Savings) or `'C'` (Current) AND `Amount` is strictly greater than 0.0. Otherwise, returns `FALSE`.

Save your program code.
[5]
Show answer & marking scheme

Worked solution

### Python 3
```python
class AccountTransaction:
def __init__(self, TransID, AccType, TransAmount):
self.__TransactionID = str(TransID)
self.__AccountType = str(AccType).upper()
self.__Amount = float(TransAmount)

def GetTransactionID(self):
return self.__TransactionID

def GetAccountType(self):
return self.__AccountType

def GetAmount(self):
return self.__Amount

def ValidateTransaction(self):
if (self.__AccountType == 'S' or self.__AccountType == 'C') and self.__Amount > 0.0:
return True
return False
```

### Java
```java
public class AccountTransaction {
private String TransactionID;
private char AccountType;
private double Amount;

public AccountTransaction(String TransID, char AccType, double TransAmount) {
this.TransactionID = TransID;
this.AccountType = AccType;
this.Amount = TransAmount;
}

public String GetTransactionID() {
return this.TransactionID;
}

public char GetAccountType() {
return this.AccountType;
}

public double GetAmount() {
return this.Amount;
}

public boolean ValidateTransaction() {
if ((this.AccountType == 'S' || this.AccountType == 'C') && this.Amount > 0.0) {
return true;
}
return false;
}
}
```

### VB.NET
```vb
Public Class AccountTransaction
Private TransactionID As String
Private AccountType As Char
Private Amount As Double

Public Sub New(ByVal TransID As String, ByVal AccType As Char, ByVal TransAmount As Double)
TransactionID = TransID
AccountType = AccType
Amount = TransAmount
End Sub

Public Function GetTransactionID() As String
Return TransactionID
End Function

Public Function GetAccountType() As Char
Return AccountType
End Function

Public Function GetAmount() As Double
Return Amount
End Function

Public Function ValidateTransaction() As Boolean
If (AccountType = "S"c OrElse AccountType = "C"c) AndAlso Amount > 0.0 Then
Return True
Else
Return False
End If
End Function
End Class
```

Marking scheme

1 mark: Class definition and 3 private attributes with appropriate data types
1 mark: Constructor method taking 3 parameters and storing them into private attributes
1 mark: Three getter functions implemented and returning respective attributes
1 mark: `ValidateTransaction()` checking `AccountType` is `'S'` or `'C'`
1 mark: `ValidateTransaction()` checking `Amount > 0.0` and returning appropriate boolean
Question 10 · Linked List 2D Array Pointer Manipulation & Traversal
5 marks
A program uses a 2D array `linkedList` of type `INTEGER` of size 10 by 2 to implement a linked list.
- The first column (index 0) stores the integer data value.
- The second column (index 1) stores the pointer to the next node in the list.
- `-1` represents a null pointer.

The global integer `startPointer` points to the first node in the linked list.
The global integer `freePointer` points to the first available node in the free list.

(a) Write program code to declare the global 2D array `linkedList` (size 10 by 2) and global pointers `startPointer` and `freePointer`.
(b) Write a procedure `initialiseList()` to set up the free list so that all 10 nodes are linked sequentially, `startPointer` is set to `-1`, and `freePointer` is set to `0`.
(c) Write a procedure `outputNodes()` that traverses the linked list from `startPointer` and prints the data values of all active nodes in sequence.

Save your program code.
Show answer & marking scheme

Worked solution

### Python Implementation

```python
# Global declarations
linkedList = [[0, 0] for _ in range(10)]
startPointer = -1
freePointer = 0

def initialiseList():
global linkedList, startPointer, freePointer
startPointer = -1
freePointer = 0
for i in range(9):
linkedList[i][0] = 0
linkedList[i][1] = i + 1
linkedList[9][0] = 0
linkedList[9][1] = -1

def outputNodes():
global linkedList, startPointer
currentPointer = startPointer
if currentPointer == -1:
print("List is empty")
else:
while currentPointer != -1:
print(linkedList[currentPointer][0])
currentPointer = linkedList[currentPointer][1]
```

### Java Implementation

```java
public class Main {
public static int[][] linkedList = new int[10][2];
public static int startPointer = -1;
public static int freePointer = 0;

public static void initialiseList() {
startPointer = -1;
freePointer = 0;
for (int i = 0; i < 9; i++) {
linkedList[i][0] = 0;
linkedList[i][1] = i + 1;
}
linkedList[9][0] = 0;
linkedList[9][1] = -1;
}

public static void outputNodes() {
int currentPointer = startPointer;
if (currentPointer == -1) {
System.out.println("List is empty");
} else {
while (currentPointer != -1) {
System.out.println(linkedList[currentPointer][0]);
currentPointer = linkedList[currentPointer][1];
}
}
}
}
```

Marking scheme

1 mark per point (Max 5 marks):
1. Declaring 2D array `linkedList` of size 10 by 2 and global pointers `startPointer` and `freePointer`.
2. Correct initialisation of `startPointer = -1` and `freePointer = 0` in `initialiseList()`.
3. Loop linking indices 0 through 8 to point to `index + 1`, and index 9 pointer set to `-1`.
4. Initialising `currentPointer` to `startPointer` and handling empty list check or loop condition `currentPointer != -1`.
5. Correct output of node data `linkedList[currentPointer][0]` and following pointer `linkedList[currentPointer][1]`.
Question 11 · Linked List 2D Array Pointer Manipulation & Traversal
5 marks
A program stores a linked list in a global 2D array `linkedList` of size 15 by 2.
- Column 0 contains string data (`STRING`).
- Column 1 contains integer pointer values (`INTEGER`).
- `startPointer` points to the first active element.
- `freePointer` points to the next available free space.

Write a procedure `insertAtHead(newItem)` that:
1. Checks if the free list is full (no space available) and outputs an appropriate message if full.
2. Allocates a node from `freePointer` and updates `freePointer` to the next free node.
3. Stores `newItem` in the allocated node.
4. Sets the pointer of the new node to point to the current `startPointer`.
5. Updates `startPointer` to point to the newly allocated node.

Save your program code.
Show answer & marking scheme

Worked solution

### Python Implementation

```python
linkedList = [["", i + 1] for i in range(15)]
linkedList[14][1] = -1
startPointer = -1
freePointer = 0

def insertAtHead(newItem):
global linkedList, startPointer, freePointer
if freePointer == -1:
print("Linked list is full. Insertion failed.")
else:
newNodeIndex = freePointer
freePointer = linkedList[freePointer][1]
linkedList[newNodeIndex][0] = newItem
linkedList[newNodeIndex][1] = startPointer
startPointer = newNodeIndex
```

### VB.NET Implementation

```vb
Module Module1
Dim linkedList(14, 1) As Object
Dim startPointer As Integer = -1
Dim freePointer As Integer = 0

Sub insertAtHead(ByVal newItem As String)
If freePointer = -1 Then
Console.WriteLine("Linked list is full. Insertion failed.")
Else
Dim newNodeIndex As Integer = freePointer
freePointer = CInt(linkedList(freePointer, 1))
linkedList(newNodeIndex, 0) = newItem
linkedList(newNodeIndex, 1) = startPointer
startPointer = newNodeIndex
End If
End Sub
End Module
```

Marking scheme

1 mark per point (Max 5 marks):
1. Procedure header taking `newItem` as parameter and check `freePointer == -1` with error message.
2. Capturing `freePointer` into a temporary variable (e.g. `newNodeIndex`).
3. Updating `freePointer` to `linkedList[freePointer][1]`.
4. Storing `newItem` into `linkedList[newNodeIndex][0]`.
5. Setting `linkedList[newNodeIndex][1] = startPointer` AND updating `startPointer = newNodeIndex`.
Question 12 · Linked List 2D Array Pointer Manipulation & Traversal
5 marks
A linked list is implemented using a 2D array `linkedList` of size 20 by 2, where column 0 stores strings and column 1 stores pointers.
`startPointer` contains the index of the first node in the list.

Write a function `searchItem(searchValue)` that:
1. Takes a string `searchValue` as a parameter.
2. Iterates through the active nodes in the linked list starting at `startPointer`.
3. Returns the array index of the node where `searchValue` is found.
4. If `searchValue` is not in the list, or the list is empty, returns `-1`.

Save your program code.
Show answer & marking scheme

Worked solution

### Python Implementation

```python
def searchItem(searchValue):
global linkedList, startPointer
currentPointer = startPointer
while currentPointer != -1:
if linkedList[currentPointer][0] == searchValue:
return currentPointer
currentPointer = linkedList[currentPointer][1]
return -1
```

### Java Implementation

```java
public static int searchItem(String searchValue) {
int currentPointer = startPointer;
while (currentPointer != -1) {
if (linkedList[currentPointer][0].equals(searchValue)) {
return currentPointer;
}
currentPointer = (int) linkedList[currentPointer][1];
}
return -1;
}
```

Marking scheme

1 mark per point (Max 5 marks):
1. Correct function header accepting `searchValue` and returning integer index.
2. Initialising traversal pointer `currentPointer` to `startPointer`.
3. Loop structure executing while `currentPointer != -1`.
4. Condition comparing node value `linkedList[currentPointer][0]` with `searchValue` and returning `currentPointer` if equal.
5. Traversing to next node `currentPointer = linkedList[currentPointer][1]` and returning `-1` after loop.
Question 13 · Linked List 2D Array Pointer Manipulation & Traversal
5 marks
An ordered linked list of integer values is stored in a 2D array `numList` of size 12 by 2.
- Column 0 contains the integer value.
- Column 1 contains the integer pointer to the next node.
- `startPointer` points to the smallest element in the list.
- `freePointer` points to the first available node in the free list.

Write a procedure `insertOrdered(newVal)` that:
1. Outputs a message if the list is full (`freePointer = -1`).
2. Allocates a node from `freePointer` and stores `newVal`.
3. Inserts the node in ascending numerical order, updating pointers correctly when:
- the node is inserted at the start of the list
- the node is inserted between two nodes or at the end of the list.

Save your program code.
Show answer & marking scheme

Worked solution

### Python Implementation

```python
numList = [[0, i + 1] for i in range(12)]
numList[11][1] = -1
startPointer = -1
freePointer = 0

def insertOrdered(newVal):
global numList, startPointer, freePointer
if freePointer == -1:
print("List full. Cannot insert.")
return

newNode = freePointer
freePointer = numList[freePointer][1]
numList[newNode][0] = newVal

if startPointer == -1 or numList[startPointer][0] >= newVal:
numList[newNode][1] = startPointer
startPointer = newNode
else:
previous = startPointer
current = numList[startPointer][1]
while current != -1 and numList[current][0] < newVal:
previous = current
current = numList[current][1]

numList[previous][1] = newNode
numList[newNode][1] = current
```

### Java Implementation

```java
public static void insertOrdered(int newVal) {
if (freePointer == -1) {
System.out.println("List full. Cannot insert.");
return;
}
int newNode = freePointer;
freePointer = numList[freePointer][1];
numList[newNode][0] = newVal;

if (startPointer == -1 || numList[startPointer][0] >= newVal) {
numList[newNode][1] = startPointer;
startPointer = newNode;
} else {
int previous = startPointer;
int current = numList[startPointer][1];
while (current != -1 && numList[current][0] < newVal) {
previous = current;
current = numList[current][1];
}
numList[previous][1] = newNode;
numList[newNode][1] = current;
}
}
```

Marking scheme

1 mark per point (Max 5 marks):
1. Check for overflow `freePointer == -1` and allocating `newNode = freePointer`, updating `freePointer`.
2. Assigning `numList[newNode][0] = newVal`.
3. Checking if new node belongs at head (`startPointer == -1` or `numList[startPointer][0] >= newVal`) and setting `numList[newNode][1] = startPointer` and `startPointer = newNode`.
4. Loop traversing with `previous` and `current` pointers to locate insertion point while `current != -1` and node value `< newVal`.
5. Adjusting pointers: `numList[previous][1] = newNode` and `numList[newNode][1] = current`.
Question 14 · Linked List 2D Array Pointer Manipulation & Traversal
5 marks
A linked list is implemented using a 2D array `linkedList` of size 10 by 2.
- Column 0 contains the data item (`STRING`).
- Column 1 contains the pointer (`INTEGER`).
- `startPointer` points to the first active element.
- `freePointer` points to the first available free list node.

Write a function `deleteNode(targetValue)` that:
1. Searches for `targetValue` in the linked list.
2. If `targetValue` is not found or list is empty, returns `FALSE`.
3. If `targetValue` is found:
- Removes the node from the active list by updating `startPointer` or the previous node's pointer.
- Adds the removed node back to the front of the free list.
- Returns `TRUE`.

Save your program code.
Show answer & marking scheme

Worked solution

### Python Implementation

```python
def deleteNode(targetValue):
global linkedList, startPointer, freePointer
if startPointer == -1:
return False

current = startPointer
previous = -1

while current != -1 and linkedList[current][0] != targetValue:
previous = current
current = linkedList[current][1]

if current == -1:
return False

if current == startPointer:
startPointer = linkedList[startPointer][1]
else:
linkedList[previous][1] = linkedList[current][1]

# Return deleted node to free list
linkedList[current][0] = ""
linkedList[current][1] = freePointer
freePointer = current

return True
```

### Java Implementation

```java
public static boolean deleteNode(String targetValue) {
if (startPointer == -1) {
return false;
}
int current = startPointer;
int previous = -1;

while (current != -1 && !linkedList[current][0].equals(targetValue)) {
previous = current;
current = (int) linkedList[current][1];
}

if (current == -1) {
return false;
}

if (current == startPointer) {
startPointer = (int) linkedList[startPointer][1];
} else {
linkedList[previous][1] = linkedList[current][1];
}

linkedList[current][0] = "";
linkedList[current][1] = freePointer;
freePointer = current;

return true;
}
```

Marking scheme

1 mark per point (Max 5 marks):
1. Check for empty list or not found returning `FALSE`.
2. Loop tracking `current` and `previous` pointers to locate `targetValue`.
3. Correct unlinking when deleting head node (`startPointer = linkedList[startPointer][1]`).
4. Correct unlinking when deleting middle/tail node (`linkedList[previous][1] = linkedList[current][1]`).
5. Returning freed node to free list (`linkedList[current][1] = freePointer; freePointer = current`) and returning `TRUE`.

Wondering how well you actually know this?

thinka is an AI practice app for IGCSE & IB students: unlimited questions, instant auto-marking, and detailed step-by-step solutions. 100,000+ students use it to confirm they actually know it, not just think they do.

Want more questions like this? Practice unlimited on thinka, instant answers included.

Start Practicing Free