Syllabus coverage
- Data types: integer, real, char, string, Boolean and date, with pseudocode types INTEGER, REAL, CHAR, STRING, BOOLEAN, DATE, ARRAY and FILE
- Select and use appropriate data types for a problem solution
- Show understanding of the purpose of a record structure, to hold a set of data of different data types under one identifier
- Write pseudocode to define a record structure, and to read data from and save data to a record structure
- Use the technical terms associated with arrays, including index, upper bound and lower bound
- Select a suitable data structure (1D or 2D array) for a given task and write pseudocode for 1D and 2D arrays
- Write pseudocode to process array data, sorting using a bubble sort
- Write pseudocode to process array data, searching using a linear search
- Show understanding of why files are needed
- Write pseudocode to handle text files that consist of one or more lines
- Show understanding that an abstract data type (ADT) is a collection of data and a set of operations on those data
- Show understanding that a stack, a queue and a linked list are examples of ADTs, and describe their key features
- Justify the use of a stack, a queue or a linked list for a given situation, and add, edit and delete data in them
- Describe how a queue, a stack and a linked list can be implemented using arrays
Part of the AS & A Level Computer Science syllabus 9618.
Data types and how to choose one
Every value in a program is declared with a data type, and the type fixes what the value can be and which operations are allowed on it. Cambridge pseudocode uses six simple data types, INTEGER, REAL, CHAR, STRING, BOOLEAN and DATE, plus the structured types ARRAY and FILE. Choosing the type is not decoration: it decides whether arithmetic will work, whether a leading zero survives, and whether the value can be validated at all.
INTEGER holds whole numbers, positive, negative or zero, and is used for counting: a quantity, a year group, the number of seats sold. REAL holds a number with a fractional part, such as a price, an average or a measurement, and it must be used whenever the result of a calculation can have a decimal part. Money is sometimes stored as an INTEGER number of pence rather than a REAL number of pounds, because binary floating point cannot store every decimal fraction exactly, so repeated additions of 0.10 can drift.
CHAR holds exactly one character, such as a grade letter or a single initial. STRING holds zero or more characters: a name, an address, a postcode, a telephone number. A telephone number and a postcode look numeric but must be STRING, because a postcode contains letters and spaces and a telephone number beginning with 0 would lose that zero if it were stored as an INTEGER.
BOOLEAN holds only TRUE or FALSE, and it is the right type for anything with two states: whether a pupil is registered, whether a book is on loan, whether a password has been entered correctly. DATE holds a calendar date, and it exists so that dates can be compared and used in calculations. The number of days between two DATE values can be calculated, which is how an age or an overdue charge is worked out; a date stored as a STRING can be displayed but cannot be treated as a date without being converted first.
- Ask four questions of the data: is it counted (INTEGER), measured or money with a fractional part (REAL), a single character (CHAR), text (STRING), one of two states (BOOLEAN) or a calendar date (DATE)?
- Use STRING, not INTEGER, for anything with a leading zero or with letters in it: telephone numbers, postcodes, product codes such as 0071.
- Use REAL only where a fractional part is genuinely possible, and INTEGER where it never is, because the type tells the reader what the value means.
- A value that is only ever compared with another date, or used to work out an interval, should be DATE rather than STRING.
| Data type | What it can hold | Typical use | Why another type would be wrong |
|---|---|---|---|
| INTEGER | A whole number, positive, negative or zero | Number of tickets sold, year group, stock level | A REAL would allow impossible values such as 2.5 tickets; a STRING could not be added up |
| REAL | A number with a fractional part | Price, average mark, mass in kilograms | An INTEGER would truncate the fraction and lose precision |
| CHAR | Exactly one character | Grade letter, middle initial, Y or N | A STRING allows more than one character, so the length is no longer guaranteed |
| STRING | Zero or more characters | Name, address, postcode, telephone number | An INTEGER loses a leading zero and cannot hold letters or spaces |
| BOOLEAN | TRUE or FALSE only | Is the book on loan?, has the fee been paid? | A STRING invites inconsistent answers such as yes, Y or true |
| DATE | A calendar date | Date of birth, date borrowed, date of the next service | A STRING can be displayed but cannot be compared or subtracted as a date |
Records: different data types under one identifier
A record is a structure that holds a set of related data of different data types under one identifier. One pupil's record might hold a last name (STRING), a date of birth (DATE), a year group (INTEGER) and whether the fees are paid (BOOLEAN). Without records you would need four separate variables for every pupil and a naming scheme to keep them together; with a record the four fields travel as one item, which can be passed to a procedure or written to a file in one go.
The structure is defined once, and the definition is a type, not a variable. TYPE names the record type and lists each field with its data type, and ENDTYPE closes the definition. A variable of that type is then declared in the usual way, and each field is reached using the variable name, a dot and the field name, for example Pupil.YearGroup.
This dot notation is accepted anywhere a variable is accepted: INPUT Pupil.LastName reads a value into the field, an assignment stores one, and OUTPUT displays one. Because a field is just a named storage location with a type, it behaves like any other variable: LastName can be compared with another STRING, DateOfBirth can be compared with today's date, and FeePaid can be used directly as a condition. A whole record can also be read from a file or written to a file in one statement when the file stores records, which is why records and files are taught together.
Records combine naturally with arrays. DECLARE Pupils : ARRAY[1:200] OF StudentRecord gives 200 records, and Pupils[7].LastName is the surname of the seventh pupil. Parallel arrays, one array of names and a separate array of marks, also work, but they can drift out of step the moment a pupil is deleted from one array and not the other; an array of records cannot drift, because element 7 holds every field belonging to pupil 7.
| Line of pseudocode | What it does |
|---|---|
| TYPE StudentRecord | Starts the definition of a record type; the name is chosen by the programmer |
| DECLARE LastName : STRING | Declares a field inside the record, with its own data type |
| DECLARE DateOfBirth : DATE | A second field, of a different type, inside the same record |
| DECLARE YearGroup : INTEGER | A third field; a record may hold as many fields as the problem needs |
| ENDTYPE | Ends the definition. No variable exists yet |
| DECLARE Pupil : StudentRecord | Declares one variable of the record type |
| Pupil.LastName <- "Okafor" | Assigns a value to one field using dot notation |
| INPUT Pupil.YearGroup | Reads a value straight into a field |
| OUTPUT Pupil.LastName, Pupil.YearGroup | Outputs fields exactly like ordinary variables |
1D arrays: index, bounds and processing
An array is a fixed number of elements of the same data type, held under one identifier and selected by an index (also called a subscript). The lower bound is the first index the array allows and the upper bound is the last, so ARRAY[1:30] has 30 elements and ARRAY[0:9] has 10. The number of elements is the upper bound minus the lower bound plus one.
Declaring an array reserves all of its storage at once: DECLARE Scores : ARRAY[1:30] OF INTEGER creates 30 integer locations, all initially undefined. An element is used exactly like a variable, with the index in square brackets, so Scores[4] <- 67 stores a mark and OUTPUT Scores[4] displays it. The index may be a variable or an expression, and that is what makes an array worth having: Scores[Index] inside a loop reaches every element in turn with a single statement.
Most array processing is one pass from the lower bound to the upper bound. A FOR loop reads the values, and a second pass totals, counts, finds the largest or works out an average. A running total must be set to 0 before the loop, never inside it, and a maximum must be initialised to the first element or to a value below any possible element, otherwise it stays at 0 and no mark is ever larger than it.
Indexing outside the declared bounds is an error. Some languages stop the program with an index error, others silently write over another variable, which is far worse because the fault appears somewhere else. Arrays are also fixed in size, so when the number of items is not known in advance the array is declared generously and a separate variable counts how many elements are actually in use.
| Term | Meaning | Example in ARRAY[1:50] OF STRING |
|---|---|---|
| Element | One storage location in the array | Names[1] is the first element |
| Index (subscript) | The value in brackets that selects an element | Names[Index] where Index is 7 selects the seventh |
| Lower bound | The smallest index allowed | 1 |
| Upper bound | The largest index allowed | 50 |
| Size | The number of elements, upper minus lower plus one | 50 elements |
| Dimension | The number of indices needed to select an element | One, so this is a 1D array |
2D arrays: data in a grid
A 2D array needs two indices to select an element, and it is the natural structure for anything laid out in rows and columns. DECLARE Seats : ARRAY[1:5, 1:3] OF BOOLEAN declares 5 rows of 3 columns, which is 15 elements, and Seats[2, 3] is the element in row 2, column 3. The first index is always the row and the second is the column, and that order has to be kept the same everywhere in the program, because Seats[3, 2] is a different element.
Reading or processing the whole array takes two loops, one inside the other. The outer loop steps through the rows and the inner loop steps through every column of the current row, so the inner loop finishes before the row changes. Reading a value into each element therefore takes one INPUT inside the inner loop, with both indices written in the brackets, and a total over the grid is a sum accumulated in the inner loop.
A 2D array is the right choice when each item is described by two facts: a seat by its row and its number, a mark by the pupil and the subject, a pixel by its x and y coordinates, a square on a board by its row and column. A 1D array is right when one index is enough, as with a list of 30 names, even though each name is itself a string of characters.
Two errors are common. The first is mixing the order of the indices so that the program reads columns where it means rows; the second is declaring an array far larger than the data, which wastes storage and makes the loops harder to follow. Decide which index is the row before writing a single line, and use the same meaning throughout.
| Declaration | Elements | What it models |
|---|---|---|
| ARRAY[1:30] OF STRING | 30 | A list of names; one index is enough |
| ARRAY[1:5, 1:3] OF BOOLEAN | 15 | A seating plan, 5 rows of 3 seats, TRUE if the seat is booked |
| ARRAY[1:20, 1:8] OF INTEGER | 160 | A marks table, 20 pupils by 8 subjects |
| ARRAY[1:8, 1:8] OF CHAR | 64 | A chessboard or draughts board |
| ARRAY[1:100, 1:100] OF INTEGER | 10 000 | An image, where each element is the colour of one pixel |
Searching an array with a linear search
A linear search (serial search) checks the elements one at a time, starting at the lower bound, until it finds the value it is looking for or runs past the last element. It makes no demand that the data be in order, which is its great strength: it is the only one of the two searches in this syllabus that works on unsorted data, and it can be used the moment a value is stored.
The algorithm needs four things: the array, the value being searched for, an index that steps through the elements, and a Boolean flag that records whether the value has been found. The index and the flag are both initialised before the loop, and the loop continues while the value has not been found and the index is still inside the array. Missing either half of that condition breaks the algorithm: without the flag it never stops when the value is found, and without the bounds check it runs past the end of the array for a value that is not there.
Inside the loop the element is compared with the search value; if they are equal the flag is set to TRUE, otherwise the index moves on by one. When the loop ends, the flag is tested to decide what to output. If the flag is TRUE the value was found at the current index; if it is FALSE the value is not in the array and the index has ended one beyond the upper bound, which is why the flag rather than the index decides what is reported.
A linear search is easy to write and needs no ordering, but it is slow on large arrays. A successful search takes between 1 comparison, if the value happens to be first, and n comparisons, if it is last; an unsuccessful search always takes n comparisons because every element must be checked. Doubling the amount of data doubles the work, so for a large amount of sorted data an algorithm that uses the order to discard half the data at a time is dramatically faster.
| Line of pseudocode | Why it is there |
|---|---|
| Found <- FALSE | Initialises the flag before the loop; without it the loop condition is undefined |
| Index <- 1 | Starts at the lower bound of the array |
| WHILE NOT Found AND Index <= 500 DO | Two conditions: stop when found, and stop at the end of the array |
| IF ProductCode[Index] = SearchCode THEN | The comparison that does the work |
| Found <- TRUE | Records the find, which ends the loop on the next test |
| ELSE | The two outcomes of the comparison, kept separate |
| Index <- Index + 1 | Moves to the next element; if this is missed the loop never ends |
| ENDIF | Closes the IF |
| ENDWHILE | Closes the loop |
| IF Found THEN OUTPUT Index ELSE OUTPUT "Not found" | Reports the result after the loop, testing the flag |
Sorting an array with a bubble sort
A bubble sort steps through the array comparing each element with the one after it, and swaps the pair whenever they are in the wrong order. On each pass the largest remaining value moves steadily towards the end of the array and stays there, which is where the name comes from. Sorting into descending order needs no change to the algorithm beyond reversing the comparison.
After the first pass the largest value is in place, after the second the second largest is in place, so n elements need at most n-1 passes. In practice the sort usually finishes sooner: if a complete pass makes no swaps then nothing was out of order, so the array must already be sorted. A Boolean flag set to FALSE at the start of every pass and to TRUE whenever a swap happens lets a REPEAT loop stop as soon as a pass is clean, which makes the algorithm much quicker on data that is nearly in order already.
Swapping two elements needs three statements and a temporary variable: copy the first value into the temporary, copy the second value into the first element, then copy the temporary into the second element. The classic mistake is two assignments without the temporary, which ends with both elements holding the same value and one value lost for ever.
A bubble sort is short, needs only one extra variable, and is simple to check by hand, but it is inefficient. With n elements the first pass makes n-1 comparisons, the next n-2, and so on, giving roughly n(n-1)/2 comparisons in the worst case, so the work grows with the square of the number of items and a large array becomes very slow. It is a sensible choice for a few dozen items, or for data that is almost sorted, and a poor choice for a file of thousands of records.
| Line of pseudocode | Purpose |
|---|---|
| REPEAT | Outer loop: one repetition is one pass through the array |
| Swap <- FALSE | Assumes the array is sorted until a swap proves otherwise |
| FOR Index <- 1 TO NumberInArray - 1 | Inner loop compares adjacent pairs; the last index must be one less than the upper bound |
| IF Names[Index] > Names[Index + 1] THEN | The comparison; change > to < for descending order |
| Temp <- Names[Index] | First statement of the three-statement swap |
| Names[Index] <- Names[Index + 1] | Second statement of the swap |
| Names[Index + 1] <- Temp | Third statement, which completes the swap without losing a value |
| Swap <- TRUE | Records that a swap happened, so another pass is needed |
| ENDIF | Closes the IF |
| NEXT | Moves to the next adjacent pair |
| UNTIL Swap = FALSE | Stops after a pass in which nothing moved |
Files: why they are needed and how they are handled
Why files are needed. Variables and arrays live in main memory, and main memory is volatile: its contents are lost when the program ends, when the computer is switched off or when the power fails. A file is held on secondary storage, so the data survives between runs, can be read back by the same program next time or by a different program, and can be copied, transferred to another computer, backed up or sent to a printer. Files also hold collections of data far too large to fit in memory at once, which can be processed one line at a time.
A text file is a sequence of characters divided into lines, and the program reads it one line at a time from the beginning to the end. Each line normally holds one record or one field, so the structure of the file has to match the structure of the program that reads it. The program has no way of knowing how many lines there are except by reaching the end, so it tests EOF, end of file, before every read; reading when the end has been reached is an error.
A file is opened before it is used and closed afterwards. OPENFILE with FOR READ opens an existing file for reading, FOR WRITE creates a new file or empties an existing one, and FOR APPEND adds new data to the end of an existing file without destroying what is already there.
READFILE reads one line into a variable, WRITEFILE writes one line, and CLOSEFILE writes any buffered data to the disk and releases the file. A program that forgets to close a file can lose the last few records it wrote.
Reading a file therefore follows a fixed pattern: open it, test EOF, read one line, process that line, and repeat until EOF is true, then close it. If the lines are records, each line is read into a record or split into fields; if the program needs to keep all of the data, each line is copied into the next element of an array as it is read, which is how a file of records becomes an array of records in memory.
| Statement | What it does | Point to remember |
|---|---|---|
| OPENFILE "pupils.txt" FOR READ | Opens an existing file so that lines can be read | The file must exist, or the open fails |
| OPENFILE "pupils.txt" FOR WRITE | Creates the file, or empties an existing one, ready to write | Any previous contents are lost, so WRITE is never used to add to a file |
| OPENFILE "pupils.txt" FOR APPEND | Opens the file ready to add after the last line | The existing lines are kept |
| READFILE "pupils.txt", LineOfText | Reads the next line into the variable | Only ever used after testing EOF |
| WRITEFILE "pupils.txt", Pupil.LastName | Writes one line to the file | Each WRITEFILE starts a new line |
| EOF("pupils.txt") | TRUE when the whole file has been read | Test it before every read, including the first |
| CLOSEFILE "pupils.txt" | Finishes with the file and flushes it to disk | Every file that is opened must be closed |
Stacks and queues as abstract data types
An abstract data type (ADT) is a collection of data together with the set of operations that can be performed on that data. It is abstract because the user of the ADT knows what each operation does but not how the data is stored or how the operations are implemented. A stack can be built from an array or from a linked list, and the program that uses the stack does not need to know which, because the operations behave the same way in both cases.
This is the same idea as abstraction elsewhere in the course: keep the essential behaviour and hide the detail. A stack is a last in, first out (LIFO) structure. Data is added with push and removed with pop, and both operations work at one end only, the top; a peek (or top) operation reads the top value without removing it.
Because only the top is accessible, the item that was pushed most recently is the first one out. Pushing onto a full stack causes overflow, and popping from an empty stack causes underflow, so a well-written implementation tests for both.
A queue is a first in, first out (FIFO) structure. Data is added at one end, the rear, with enqueue, and removed from the other end, the front, with dequeue, so items leave in exactly the order they arrived. A queue is the right structure whenever fairness or arrival order matters: a print spooler, a keyboard buffer, a queue of customers, or a set of processes waiting for the processor are all queues.
Choosing between them is a question about which item must be handled next: the most recent item first means a stack, and the oldest item first means a queue. Say which operation is used and why that order gives the behaviour the situation needs, because a description of the structure without the justification does not answer a justify question.
| Situation | Structure | Why |
|---|---|---|
| Undo in a word processor | Stack | The most recent edit must be undone first, so LIFO order is exactly right |
| Back button in a browser | Stack | Each page visited is pushed; going back pops the most recent one |
| Checking that brackets in an expression are balanced | Stack | Each closing bracket must match the most recently opened one |
| Print spooler in an operating system | Queue | Jobs should print in the order they were sent, so FIFO keeps it fair |
| Characters typed at a keyboard while the processor is busy | Queue | Keystrokes must be delivered in the order they were typed or the text is scrambled |
| Calls waiting to be answered in a call centre | Queue | The caller who has waited longest is answered next |
Linked lists, and implementing all three with arrays
A linked list stores each item in a node. A node holds the data and a pointer to the next node, the last node's pointer holds a null value to show the list has ended, and a separate start (or head) pointer gives the position of the first node. The nodes need not be next to one another in memory, which is what makes a linked list different from an array: the list can grow and shrink while the program runs, and no maximum size has to be declared in advance.
To traverse a linked list the program starts at the start pointer and follows the pointers node by node until it reaches null; the nth item cannot be reached directly, so a linked list is slower than an array for reading a particular item but much faster for inserting and deleting.
To insert a node, the new node's pointer is set to the node it will come before and the previous node's pointer is set to the new node. To delete a node, the previous node's pointer is set to skip over it. Neither operation moves any of the other items, whereas inserting into the middle of an array means shifting every later element up one place.
All three ADTs can be implemented using arrays, which is how they are usually examined. A stack uses a 1D array and a single integer, Top, which holds the index of the current top element and is 0 when the stack is empty: push tests that Top is below the upper bound, then increments Top and stores the value; pop tests that Top is above 0, reads the value and decrements Top. Top equal to the upper bound means the stack is full, and Top equal to 0 means it is empty.
A queue uses a 1D array with two integers, Front and Rear, which mark the two ends; enqueue increments Rear and stores, dequeue reads the element at Front and increments Front. In a simple array implementation the space at the front is never reused, so the queue creeps towards the end of the array and reports itself full while most of the array is empty; a circular queue solves this by making Rear wrap round to the start with MOD, reusing the vacated space. A linked list uses two parallel arrays, one holding the data and one holding the index of the next node, plus a start pointer and a list of free positions, so that inserting and deleting only ever changes the integer pointers.
| Structure | Stored as | What marks the ends | What an operation involves |
|---|---|---|---|
| Stack | 1D array plus an integer Top | Top is 0 when empty, upper bound when full | Push: Top <- Top + 1, then store. Pop: read, then Top <- Top - 1 |
| Queue | 1D array plus Front and Rear | Front = Rear means empty in a simple implementation | Enqueue: Rear <- Rear + 1, then store. Dequeue: read at Front, then Front <- Front + 1 |
| Circular queue | 1D array plus Front, Rear and a count or a full flag | Rear wraps round with MOD so the free space at the front is reused | Enqueue: Rear <- (Rear + 1) MOD Size, then store |
| Linked list | Parallel arrays Data and Next, plus Start and a free list | Next holding a null value marks the last node | Insert: set the new node's Next, then the previous node's Next. Delete: point the previous node past the deleted node |
Key terms you must be able to define
- Data type
- The kind of value a variable, field or array element can hold, which also fixes the operations allowed on it. Cambridge pseudocode uses INTEGER, REAL, CHAR, STRING, BOOLEAN and DATE, with ARRAY and FILE as structured types.
- Record
- A structure that holds a set of data of different data types under one identifier. The type is defined once with TYPE ... ENDTYPE, and each field is reached using the record identifier, a dot and the field name.
- Field
- One named component of a record, with its own identifier and data type, for example LastName : STRING or DateOfBirth : DATE inside a pupil record.
- Index (subscript)
- The value written in brackets after an array identifier that selects one element, for example the 4 in Scores[4]. It may be a constant, a variable or an expression.
- Lower bound
- The smallest index an array allows. In ARRAY[1:30] the lower bound is 1; in ARRAY[0:9] it is 0.
- Upper bound
- The largest index an array allows. In ARRAY[1:30] the upper bound is 30, and the array holds upper bound minus lower bound plus one, which is 30, elements.
- 2D array
- An array whose elements are selected by two indices, the first for the row and the second for the column, used for data laid out in a grid such as a seating plan or a table of marks.
- Linear search
- A search that examines each element of an array in turn from the lower bound until the value is found or the end of the array is reached. It works on unsorted data and takes at most n comparisons for n elements.
- Bubble sort
- A sort that repeatedly compares adjacent elements and swaps those in the wrong order, so that on each pass the next largest value moves to its final position. It stops early when a complete pass makes no swaps.
- Text file
- A file held on secondary storage as a sequence of characters divided into lines, read one line at a time from the beginning to the end, with EOF tested before every read.
- Abstract data type (ADT)
- A collection of data together with the set of operations that can be performed on that data, where the user of the ADT knows what the operations do but not how the data or the operations are implemented.
- Stack
- A last in, first out (LIFO) ADT in which data is added with push and removed with pop at one end only, the top. Pushing onto a full stack causes overflow; popping an empty stack causes underflow.
- Queue
- A first in, first out (FIFO) ADT in which data is added at the rear with enqueue and removed from the front with dequeue, so items leave in the order in which they arrived.
- Linked list
- An ADT in which each item is held in a node containing the data and a pointer to the next node, with a start pointer for the first node. Items can be inserted and deleted by changing pointers, without moving the other items, and the list can grow at run time.
Applied to real systems
9618 sets its questions inside systems you already use - a phone, a school network, a supermarket till, a website, a bank. These show how to apply the theory to a context you have not seen before, then you write your own.
Every edit a user makes is pushed onto an undo stack, and Ctrl+Z pops the most recent one off. The behaviour is exactly LIFO: after typing a sentence, changing a font and deleting a word, the first undo reverses the deletion, because that was the last thing done. A queue would be useless here, because it would reverse the oldest edit first and leave the most recent mistakes in place. The same structure, with a limit on its depth, explains why a program only offers a certain number of undo steps.
When several documents are sent to a printer they are placed in a spool queue and printed in the order they arrived, so a small one-page job sent first is not overtaken by a 200-page report sent two seconds later. The operating system enqueues each job at the rear and dequeues from the front, and it needs the queue because the processor can accept jobs far faster than the printer can print them. The queue is also the buffer that lets each program finish and close while its output is still waiting.
A playlist of tracks behaves like a linked list: each track is a node, and the player moves to the next track by following the pointer rather than by calculating a position in an array. Adding a track in the middle, or removing one, only changes two pointers, so the rest of the list does not move and the playlist can be any length. This is why a playlist can be edited while it is playing, which an array with a declared upper bound of, say, 100 tracks could not do gracefully.
A school stores one line per pupil in a text file, with the fields in a fixed order (surname, forename, date of birth, year group, fees paid), and the program declares a record type with a field for each. The program opens the file for reading, tests EOF, reads a line, splits it into the fields of a record, copies the record into the next element of an array of records, and closes the file. Saving the data works the other way round, and using APPEND rather than WRITE means a newly admitted pupil can be added without rewriting the whole file.
A screen with 12 rows of 20 seats is held as ARRAY[1:12, 1:20] OF BOOLEAN, where TRUE means the seat is booked. Booking a seat checks the element and sets it, and displaying the screen is a pair of nested loops that prints a row of 20 symbols for each of the 12 rows. The two indices are exactly the two facts that identify a seat, which is the test for choosing a 2D array over a 1D one.
Flashcards
Click a card to flip it. Mark honestly — the tracker uses this.
Exam-style questions
8 questions, 26 marks. Write your answer, then reveal the mark scheme and tick each point you actually made. Answering honestly here is what makes the rest of the site useful.
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Mark scheme — tick each point you actually made
Exam technique for this topic
- Write pseudocode in the guide's syntax, not in English with code words mixed in: DECLARE Name : INTEGER, assignment with <-, IF ... THEN ... ELSE ... ENDIF, FOR ... NEXT, WHILE ... ENDWHILE, and indentation of two spaces for each level. Marks are awarded for the structure as well as the logic, so a correct algorithm written as a paragraph scores little.
- For any search or sort, count the marks and make sure you have written that many separate pieces of logic: initialisation, loop condition, comparison, action, increment or swap, and the result. In a linear search answer the loop condition needs both 'not found' and 'index within bounds', and in a bubble sort answer the swap needs a temporary variable.
- Read the question for the detail that changes the answer: the lower bound of the array, whether the data is sorted, whether the file is opened for writing or appending, and whether the value may not be present. A search that never reports 'not found' and a sort that reads past the upper bound are the two most common failures in this section.
- When a question asks you to justify a data type, a structure or an ADT, give the reason from the situation rather than a definition: 'DATE, because the fine is worked out from the number of days between the borrow date and today' or 'a queue, because the jobs must print in the order they were sent'.
- Questions on the ADTs are answered in words, not pseudocode: name the operations (push and pop, enqueue and dequeue, insert and delete by pointer), say which end they work on, and where a question asks about implementation, name the pointers (Top, Front and Rear, Start and the next-node array) and say what changes when data is added or removed.