9618/42

Computer Science 9618/42October/November 2023

Cambridge A-Level · Practical · worked solutions for every part, with the mark scheme

3
questions
75
marks
150
minutes

Topics Programming Paradigms (Procedural and Object-oriented) · Algorithms and Abstract Data Types · File Processing and Exception Handling · Recursion

Q1Algorithms and Abstract Data TypesProgramming Paradigms (Procedural and Object-oriented)File Processing and Exception HandlingFree sample

Open the evidence document, evidence.doc

Make sure that your name, centre number and candidate number appear on every page of this document. This document must contain your answers to each question.

Save this evidence document in your work area as:

evidence_ followed by your centre number_candidate number, for example: evidence_zz999_9999

A class declaration can be used to declare a record.

If the programming language used does not support arrays, a list can be used instead.

One source file is used to answer Question 1. The file is called StackData.txt

A program stores lower-case letters in two stacks.

One stack stores vowels (a, e, i, o, u) and one stack stores consonants (letters that are not vowels).

Each stack is implemented as a 1D array.

(a)
(i)

Write program code to declare two 1D global arrays: StackVowel and StackConsonant.

Each array needs to store up to 100 letters. The index of the first element in each array is 0.

If you are writing in Python, include declarations using comments.

Save your program as Question1_N23.

Copy and paste the program code into part 1(a)(i) in the evidence document.

2M
DifficultyEasy
Worked solution

Answer

# global array StackVowel[0:99]
StackVowel = [''] * 100
# global array StackConsonant[0:99]
StackConsonant = [''] * 100
Final answer

See program code

Detailed explanation

Background Concept

A stack is a last-in, first-out data structure. In this question, each stack is being implemented using a 1D array. That means we reserve storage first, then use a separate pointer to keep track of where the next item should go.

In Python, there is no built-in fixed-size array in the same sense used by exam questions, so the usual exam approach is to use a list of the required size and add a comment to show the intended declaration. Because the arrays must store up to 100 letters and the first index is 0, the valid positions are 0 to 99.

Understanding the Question

This part only asks for the two global arrays, not the pointers and not any procedures yet. The key details are:

  • there are two stacks
  • each is a 1D array
  • each must hold 100 letters
  • indexing starts at 0
  • Python answers should include declaration comments

So the job here is to create storage for both stacks in global scope.

Approach

The simplest Python representation is a list with 100 elements already created. That matches the exam idea of a fixed-size array. A blank string is a suitable placeholder value for each unused position.

Because the question specifically mentions global arrays, the declarations should be written outside any function or procedure.

Step-by-Step Reasoning

First, create the vowel stack storage:

  • the name must be StackVowel
  • it must be global
  • it must have 100 positions
  • a Python list of [''] * 100 gives exactly 100 string slots

Then do the same for the consonant stack:

  • the name must be StackConsonant
  • it must also have 100 positions

The comments are included because the paper explicitly says Python candidates should show declarations using comments. That helps show the examiner that you understand these are intended as fixed-size global arrays, not just ordinary variable-length lists.

Key Takeaways

  • A stack can be implemented using a 1D array plus a pointer.
  • If indexing starts at 0 and there are 100 items, the last valid index is 99.
  • In Python practical papers, declaration comments are often used to show intended data structures.

Common Mistakes

  • Declaring only one array instead of both arrays.
  • Creating empty lists with no size, which does not match the fixed-size array requirement as clearly.
  • Using 1 to 100 as the index range even though the question says the first index is 0.
  • Putting the arrays inside a function, which would make them local instead of global.

Things to Be Careful About

  • Use the exact names StackVowel and StackConsonant.
  • Make sure each list has 100 elements, not 99 or 101.
  • In Python, the comment is not a substitute for the actual list creation; you should show both the declaration comment and the usable storage.
Techniques used
declare fixed-length global arraysuse list initialisation to represent stack storagematch array bounds to a 0-based index range
(ii)

The global variable VowelTop is a pointer that stores the index of the next free space in StackVowel.

The global variable ConsonantTop is a pointer that stores the index of the next free space in StackConsonant.

VowelTop and ConsonantTop are both initialised to 0.

Write program code to declare and initialise the two variables.

If you are writing in Python, include declarations using comments.

Save your program.

Copy and paste the program code into part 1(a)(ii) in the evidence document.

1M
DifficultyEasy
Worked solution

Answer

# global integer VowelTop
VowelTop = 0
# global integer ConsonantTop
ConsonantTop = 0
Final answer

See program code

Detailed explanation

Background Concept

When a stack is implemented with an array, a pointer is needed to track the current top position. In this question, the pointer does not store the index of the current top item. Instead, it stores the index of the next free space. That is an important detail.

If the next free space is 0, the stack is empty because no items have been placed yet. After one push, the item is stored at index 0 and the pointer becomes 1.

Understanding the Question

This part tells you exactly what the two global variables mean:

  • VowelTop stores the next free position in StackVowel
  • ConsonantTop stores the next free position in StackConsonant
  • both start at 0

So you are not choosing a design here; you are implementing the pointer design the question gives you.

Approach

Declare each pointer as a global integer variable and set it to 0. In Python, include comments to show the declaration type, because Python itself does not require type declarations.

Step-by-Step Reasoning

VowelTop = 0 means the vowel stack is empty and the first vowel pushed will go into index 0.

ConsonantTop = 0 means the consonant stack is also empty and the first consonant pushed will go into index 0.

These variables must be global because later procedures and functions such as PushData(), PopVowel() and PopConsonant() all need to update them.

Key Takeaways

  • A stack pointer can represent the next free slot rather than the current top item.
  • An empty stack is often represented by pointer value 0 when using 0-based indexing and next-free-space logic.
  • Global state is needed here because multiple routines share the same stacks and pointers.

Common Mistakes

  • Setting the pointers to -1, which would be a different stack design from the one described.
  • Forgetting that the variables must be global.
  • Initialising one pointer but not the other.

Things to Be Careful About

  • Use the exact variable names and casing from the question.
  • Keep the meaning of the pointer consistent throughout the whole program: next free space, not current top item.
  • If later code assumes a different meaning for the pointer, the push and pop logic will not match.
Techniques used
declare global pointer variablesinitialise stack top pointersrepresent the next free position with an integer index
(b)
(i)

The procedure PushData() takes one letter as a parameter.

If the parameter is a vowel, it is pushed onto StackVowel and the relevant pointer updated.

If the stack is full, a suitable message is output.

If the parameter is a consonant, it is pushed onto StackConsonant and the relevant pointer updated.

If the stack is full, a suitable message is output.

You do not need to validate that the parameter is a letter.

Write program code for PushData().

Save your program.

Copy and paste the program code into part 1(b)(i) in the evidence document.

6M
DifficultyMedium
Worked solution

Answer

def PushData(Letter):
    global VowelTop, ConsonantTop
    if Letter in ['a', 'e', 'i', 'o', 'u']:
        if VowelTop < 100:
            StackVowel[VowelTop] = Letter
            VowelTop += 1
        else:
            print('Vowel stack full')
    else:
        if ConsonantTop < 100:
            StackConsonant[ConsonantTop] = Letter
            ConsonantTop += 1
        else:
            print('Consonant stack full')
Final answer

See program code

Detailed explanation

Background Concept

A push operation adds an item to the top of a stack. With an array-based stack, that means:

  1. check whether there is space
  2. store the item at the next free position
  3. move the pointer on to the next free position

Because this question has two stacks, the procedure must first decide which stack the letter belongs in. The question defines vowels as a, e, i, o, u, and everything else is treated as a consonant. It also says you do not need to validate whether the input is actually a letter.

Understanding the Question

PushData() receives one lower-case character. If it is a vowel, it must go into StackVowel. Otherwise it must go into StackConsonant.

For either stack, if it is full, the program must output a suitable message instead of writing beyond the end of the array.

The parent stem matters here because:

  • both arrays are global and size 100
  • both pointers start at 0
  • the pointer stores the next free space

Approach

Use a membership test to decide whether the character is a vowel. Then, for the chosen stack:

  • test whether the top pointer is still below 100
  • if so, store the letter at that index
  • increment the pointer
  • otherwise output a full-stack message

This is the standard array-based push pattern.

Step-by-Step Reasoning

The procedure needs global VowelTop, ConsonantTop because those values must be changed permanently, not just inside the function.

The condition Letter in ['a', 'e', 'i', 'o', 'u'] separates vowels from consonants.

If it is a vowel:

  • VowelTop < 100 checks whether there is room
  • if true, store the letter in StackVowel[VowelTop]
  • then do VowelTop += 1

That order matters. Because the pointer stores the next free space, the item goes into the current pointer position first, and only then does the pointer move up.

If VowelTop is already 100, the stack is full. The last valid index is 99, so 100 means there is no free space left.

The consonant branch is exactly the same idea but uses StackConsonant and ConsonantTop.

A strong exam answer keeps the two branches parallel so the logic is easy to follow and easy to mark.

Key Takeaways

  • Push on an array-based stack means store first, then increment the next-free pointer.
  • Overflow must be checked before writing to the array.
  • When two similar data structures exist, it is often best to write matching logic for both.

Common Mistakes

  • Incrementing the pointer before storing the letter, which skips index 0 and misplaces every later item.
  • Testing <= 100 instead of < 100, which allows an attempt to write to index 100.
  • Forgetting the global declaration in Python, so the pointer update does not affect the real stack.
  • Using a vowel test that misses one of the vowels.

Things to Be Careful About

  • The pointer represents the next free slot, not the current top element.
  • The full condition is when the pointer reaches 100, because indices run from 0 to 99.
  • The question says lower-case letters, so a lower-case vowel check is sufficient.
  • You do not need input validation here, so do not waste time adding it unless you are certain it will not break the required logic.
Techniques used
classify data using a membership testpush an item onto the correct stackcheck for stack overflow before storing dataupdate the top pointer after insertion
(ii)

The file StackData.txt stores 100 lower-case letters.

The procedure ReadData() reads each letter from the file and uses PushData() to push each letter onto its appropriate stack.

Use appropriate exception handling if the file does not exist.

Write program code for ReadData().

Save your program.

Copy and paste the program code into part 1(b)(ii) in the evidence document.

6M
DifficultyMedium
Worked solution

Answer

def ReadData():
    try:
        File = open('StackData.txt', 'r')
        for Line in File:
            Letter = Line.strip()
            PushData(Letter)
        File.close()
    except FileNotFoundError:
        print('File does not exist')
Final answer

See program code

Detailed explanation

Background Concept

Sequential file processing means reading a file one item after another from start to end. Here, StackData.txt contains 100 lower-case letters, one per line. A typical routine must:

  • open the file
  • read each line
  • convert the raw line into the required data item
  • process that item
  • close the file

Exception handling is used so the program does not crash if the file is missing. In Python, attempting to open a file that does not exist raises FileNotFoundError.

Understanding the Question

This part does not ask you to decide which stack to use. That logic is already inside PushData(). ReadData() only needs to:

  • read the letters from StackData.txt
  • pass each letter to PushData()
  • use appropriate exception handling if the file does not exist

So the key idea is delegation: reading is done here, stack classification is done in the other procedure.

Approach

Put the file opening and reading inside a try block. Read each line in turn, remove the newline using strip(), then send the cleaned letter to PushData(). If opening the file fails, catch the exception and print a suitable message.

Step-by-Step Reasoning

File = open('StackData.txt', 'r') opens the source file for reading.

for Line in File: loops through every line in order. Since the file stores one lower-case letter per line, each iteration represents one letter.

Letter = Line.strip() removes the newline character. Without this, the value passed to PushData() would be something like 'a\n' rather than 'a', which would break the vowel test.

PushData(Letter) then pushes the cleaned character onto the correct stack.

File.close() closes the file once reading has finished.

If the file cannot be opened, control moves to the except FileNotFoundError: block, and the program outputs a suitable message instead of stopping with an error.

Key Takeaways

  • Read sequential text files one line at a time when each line holds one item.
  • Clean line-based input before processing it.
  • Use exception handling to make file operations safe.
  • Keep routines focused: one routine reads data, another decides where to store it.

Common Mistakes

  • Forgetting to remove the newline from each line.
  • Reading the file but never calling PushData().
  • Omitting exception handling, so the program crashes if the file is missing.
  • Using the wrong filename or wrong file mode.

Things to Be Careful About

  • The filename must match exactly: StackData.txt.
  • strip() is important here because each line ends with a line break.
  • If you use explicit open(), remember to close the file after reading.
  • The question says the file stores 100 letters, but a loop that reads until the file ends is still appropriate and safe.
Techniques used
open a text file for readingiterate through each record in a sequential filestrip line endings from input datacall a procedure for each item readhandle a missing-file exception
(c)

The function PopVowel() removes and returns the data at the top of StackVowel and updates the relevant pointer(s).

The function PopConsonant() removes and returns the data from the top of StackConsonant and updates the relevant pointer(s).

If either stack is empty, the string "No data" must be returned.

Write program code to declare PopVowel() and PopConsonant().

Save your program.

Copy and paste the program code into part 1(c) in the evidence document.

5M
DifficultyMedium
Worked solution

Answer

def PopVowel():
    global VowelTop
    if VowelTop == 0:
        return 'No data'
    else:
        VowelTop -= 1
        return StackVowel[VowelTop]


def PopConsonant():
    global ConsonantTop
    if ConsonantTop == 0:
        return 'No data'
    else:
        ConsonantTop -= 1
        return StackConsonant[ConsonantTop]
Final answer

See program code

Detailed explanation

Background Concept

A pop operation removes and returns the top item from a stack. With the pointer design used in this question, the pointer stores the next free space, not the current top item. That changes the order of operations.

If the stack is not empty:

  1. move the pointer back by 1
  2. read and return the item at that index

If the pointer is 0, the stack is empty and a pop would cause underflow. The question tells you exactly what to return in that case: No data.

Understanding the Question

You must write two separate functions:

  • PopVowel() for StackVowel
  • PopConsonant() for StackConsonant

Each must:

  • remove and return the top item
  • update the correct pointer
  • return No data if the relevant stack is empty

The exact return string matters here because later code in the main program will test for it.

Approach

Use the same pattern in both functions:

  • if the relevant top pointer is 0, return No data
  • otherwise decrement the pointer and return the element at the new pointer position

This mirrors the push logic used earlier.

Step-by-Step Reasoning

Take PopVowel() first.

global VowelTop is needed because the function changes the actual pointer.

if VowelTop == 0: checks whether the stack is empty. Since the pointer stores the next free space, 0 means no items have ever been pushed or all pushed items have been popped.

If it is empty, return No data immediately.

Otherwise:

  • do VowelTop -= 1
  • then return StackVowel[VowelTop]

Why decrement first? Suppose there is one item in the stack. After it was pushed, VowelTop became 1. The top item is actually at index 0. So to access the top item correctly, you must move the pointer back first.

PopConsonant() is identical in structure, but it uses ConsonantTop and StackConsonant.

Key Takeaways

  • With a next-free-space pointer, pop means decrement first, then access the array.
  • Underflow happens when trying to pop from an empty stack.
  • Returning a fixed message such as No data lets the main program detect failure cleanly.

Common Mistakes

  • Returning StackVowel[VowelTop] before decrementing, which reads the next free slot instead of the top item.
  • Forgetting to return No data exactly as specified.
  • Updating the wrong pointer in one of the functions.
  • Forgetting global, so the real pointer does not change.

Things to Be Careful About

  • The empty test is == 0, not < 0.
  • The return string must match exactly because the main program compares against it.
  • Keep the logic for the two functions separate; do not accidentally read from the vowel array using the consonant pointer or vice versa.
Techniques used
check for stack underflowdecrement the top pointer before accessreturn the removed top itemduplicate the pop pattern for two stacks
(d)

The program first needs to call ReadData() and then:

  1. prompt the user to input their choice of vowel or consonant
  2. take, as input, the user’s choice
  3. depending on the user’s choice, call PopVowel() or PopConsonant() and store the return value.

The three steps are repeated until 5 letters have been successfully returned and stored.

If either stack is empty at any stage, an appropriate message must be output.

Once 5 letters have been successfully returned and stored, they are output on one line, for example:

abyti

(i)

Write program code for the main program.

Save your program.

Copy and paste the program code into part 1(d)(i) in the evidence document.

6M
DifficultyMedium-Hard
Worked solution

Answer

ReadData()
ReturnedLetters = []

while len(ReturnedLetters) < 5:
    Choice = input('Enter vowel or consonant: ')
    if Choice == 'vowel':
        Letter = PopVowel()
        if Letter == 'No data':
            print('Vowel stack empty')
        else:
            ReturnedLetters.append(Letter)
    elif Choice == 'consonant':
        Letter = PopConsonant()
        if Letter == 'No data':
            print('Consonant stack empty')
        else:
            ReturnedLetters.append(Letter)

print(''.join(ReturnedLetters))
Final answer

See program code

Detailed explanation

Background Concept

The main program is the control section that coordinates previously written routines. In this question, the main program does not implement stack operations directly. Instead, it:

  • loads the stacks from the file
  • asks the user which stack to pop from
  • calls the appropriate pop function
  • stores successful results
  • stops only after 5 letters have been successfully returned

The phrase successfully returned is important. It means the count should only increase when a real letter is obtained, not when the function returns No data.

Understanding the Question

The order of actions is given very clearly:

  1. call ReadData() first
  2. prompt and input the user's choice
  3. depending on that choice, call PopVowel() or PopConsonant() and store the returned value
  4. repeat until 5 letters have been successfully returned and stored
  5. if a stack is empty, output an appropriate message
  6. after 5 successful letters, output them on one line

So this is a loop-control problem as much as it is a stack problem.

Approach

A good structure is:

  • call ReadData() once at the start
  • create a list to store returned letters
  • use a while loop that continues until the list length is 5
  • inside the loop, get the user's choice
  • call the correct pop function
  • if the return value is No data, print an empty-stack message and do not store it
  • otherwise append the letter to the list
  • after the loop, join the five letters into one string and print it

Step-by-Step Reasoning

ReadData() must happen before any popping, otherwise both stacks would still be empty.

ReturnedLetters = [] creates a place to store the successful results in order.

while len(ReturnedLetters) < 5: makes the loop continue until exactly 5 successful letters have been stored. This is better than repeating 5 times, because an empty-stack result must not count.

Choice = input('Enter vowel or consonant: ') gets the user's instruction.

If the choice is vowel, the program calls PopVowel(). The returned value is stored in Letter.

Then the program checks whether Letter == 'No data'.

  • If yes, the vowel stack is empty, so a message is output.
  • If no, a real letter was returned, so it is appended to ReturnedLetters.

The consonant branch works the same way with PopConsonant().

Finally, print(''.join(ReturnedLetters)) outputs the 5 collected letters on one line with no spaces, which matches the format shown in the question.

A slightly more defensive program could also handle invalid input, but the question does not require that, so a clean if/elif answer is sufficient.

Key Takeaways

  • Count successful outcomes, not just loop iterations, when failure is possible.
  • Keep stack logic inside the pop functions and use the main program only for control flow.
  • Build a final string by collecting characters in order and joining them.

Common Mistakes

  • Using a loop that repeats exactly 5 times even if some pops return No data.
  • Forgetting to call ReadData() before the loop.
  • Appending No data to the result list instead of rejecting it.
  • Printing each letter separately instead of one combined line at the end.

Things to Be Careful About

  • Compare with the exact string No data.
  • Only append when a real letter is returned.
  • The final output must be one line, so joining the list is a good Python approach.
  • If you use else instead of elif, be sure you are not accidentally treating every non-vowel input as consonant unless that is your intended design.
Techniques used
call an initial loading procedurerepeat input until a target count is reachedbranch on the user's choicestore only successful pop resultsconcatenate collected characters for final output
(ii)

Test your program with the following inputs:

vowel
consonant
consonant
vowel
vowel

Take a screenshot of the output.

Save your program.

Copy and paste the screenshot into part 1(d)(ii) in the evidence document.

1M
DifficultyMedium-Easy
Worked solution

Answer

Using the inputs vowel, consonant, consonant, vowel, vowel:

Enter vowel or consonant: vowel
Enter vowel or consonant: consonant
Enter vowel or consonant: consonant
Enter vowel or consonant: vowel
Enter vowel or consonant: vowel
uxsoe
Final answer

uxsoe

Detailed explanation

Background Concept

To predict the output of a stack program, you must remember that stacks are last-in, first-out. The most recently pushed item is the first one popped.

Because ReadData() reads the file from top to bottom and pushes each letter onto its appropriate stack, the top of each stack will contain the last matching letter found in the file.

Understanding the Question

This part is not asking for new code. It is asking you to run the finished program using these five choices:

  • vowel
  • consonant
  • consonant
  • vowel
  • vowel

So we must work out exactly which letters those five pop operations return after the file has been loaded.

Approach

Split the file contents into two conceptual stacks:

  • all vowels in the order they are read
  • all consonants in the order they are read

Then reverse your thinking for popping, because the last item pushed is on top.

Take the five choices one by one and record each returned character.

Step-by-Step Reasoning

From StackData.txt, the last few vowels read are:

  • ... i, u, e, o, u

So after all pushes, the top of the vowel stack is the final u, then below it o, then below that e.

The last few consonants read are:

  • ... g, j, k, n, c, s, x

So the top of the consonant stack is x, then below it s, then below that c.

Now apply the required inputs in order.

  1. vowel → pop from vowel stack → returns u
  2. consonant → pop from consonant stack → returns x
  3. consonant → pop from consonant stack again → returns s
  4. vowel → next vowel pop → returns o
  5. vowel → next vowel pop → returns e

So the five returned letters are:

  • u
  • x
  • s
  • o
  • e

Joined together on one line, the output is uxsoe.

No empty-stack message appears in this test because both stacks still contain plenty of data.

Key Takeaways

  • For stack tracing, always find the last matching items read from the file.
  • A mixed input sequence can alternate between two separate stacks.
  • The final displayed string is the successful pop results in the order they were returned.

Common Mistakes

  • Reading from the start of the file instead of from the top of the stack when predicting pops.
  • Mixing vowel and consonant order together instead of treating them as separate stacks.
  • Forgetting that the result is output as one combined line, not as separate letters.

Things to Be Careful About

  • Use the final loaded stack contents, not the original file order, when deciding pop results.
  • After one pop, the next item from that same stack becomes the new top.
  • The exact output shown depends on the prompt text in your program, but the key returned string here is uxsoe.
Techniques used
trace data loaded from a file into two stacksidentify the top items using last-in first-out ordersimulate the sequence of pop operationsform the final output string from returned letters

The rest of this paper

2 more questions
  • Q2Programming Paradigms (Procedural and Object-oriented) · Recursion17M
  • Q3Programming Paradigms (Procedural and Object-oriented)31M
Loading the full paper…